はじめに
みなさん、supabaseというサービスをご存知でしょうか?
本記事では、supabaseとは?というところから、EdgeFunctionを通じ環境構築、機能利用、CLI接続などなど、、、実際に動かしながらご説明できればと思います。
supabaseとは
supabaseは、オープンソースのBackend as a Service(BaaS/バース)プラットフォームです。
BaaSとは簡単に言えば、バックエンド機能を簡単に利用できるクラウドサービスです。利点としてはやはり簡単に始められる、というところ。フロント側のアプリケーション開発を重視したい場合など、迅速な開発が可能になります。
代表的なBaaSとしては、今回紹介するsupabaseの他、FirebaseやAWS Amplify、Azure App Serviceなどが挙げられます。
(AWS Amplify、Azure App ServiceどちらもSPAの静的デプロイでしか利用したことなかった。。)
supabaseが提供している機能としては、PostgreSQLを基盤とするデータベース、リアルタイム機能、認証、ストレージなど様々あります。
料金体系については、$0〜利用可能です。本記事は無料範囲内での利用を想定しています。メモリやストレージをアップさせるには追加料金で利用可能となります。
詳しい料金についてはこちら→supabase公式 料金体系
無料版は一週間利用がないと、停止状態となります。
停止状態の場合、外部よりアクセスが不可となります。再開するにはsupabaseダッシュボードにログイン後、リストアが必要です。サイズにもよりますが、リストアには数分がかかります。
supabaseでプロジェクトを作成してみる
では早速、supabaseへアクセスし、便利なバックエンド機能というものを実感してみましょう。
supabaseのサイトへアクセスします
作成したOrganization配下にProjectを作成します。
するとダッシュボートが表示されます。Project名の横の作成中くるくるが
↓
この様にステータスがグリーンであればOKです。
CLIでsupabaseへアクセスしてみる
supabase CLIを使用してローカル環境からアクセスしてみます。
参照:supabase DOCS -CLI-
まずははじめにCLIをbrewでインストールしていきます。
brew install supabase/tap/supabase
次に個人アクセス用のトークンを利用して、ローカル環境とsupabaseを接続します。
Enterで自動的にsupabaseのページへ遷移します。
ここでアクセストークンが発行され、ローカル環境と接続されます。
オプションでトークン名を指定し、アクセストークン作成、接続も可能です
supabase login –name “トークン”
次に実際に接続できるようになったのか、見てみましょう。
Supabaseで作成されたプロジェクト一覧を表示するコマンドを実行してみます。
supabase projects list
先ほど作成したプロジェクトが一覧で表示されていればOKです!
ローカル環境のプロジェクト作成する箇所にて初期化処理をします。
今回Vscodeにてフォルダを作成し、以下コマンド実行します。
supabase init
VScodeで開発を行う場合、上記画像の様にコマンド実行後
Generate VS Code settings for Deno? [y/N]
という質問がされます。supabaseは"Deno"🦕というJS/TSランタイムで作成されています。(Node.jsの制作者が作成したセキュリティ面を改良したもの)そのためローカル環境で利用する際、自動的にDenoの設定も同時に行うか、という質問です。ありがたくy
入力で自動設定してもらいます。
EdgeFunctionを作成してみる
次に、supabaseのEdge Functionsを使用し、サーバーレスな関数を作成してみます。
参照:supabase DOCS -Edge Functions-
supabaseのダッシュボードの左側ドロワーよりEdgeFunctionを選択し、遷移します。
初めて作成する場合、以下の様な画面が表示されます。(すでにFunctionがある場合、Deploy a new function
のボタンより同様画面が表示されます。)
実際のダッシュボード上では、FUNCTION_NAMEはhello-world
、REFERENCE_IDは自身の作成したプロジェクトに紐づくIDが表記されています。
FUNCTION_NAMEは新規で作成したい名前を任意で入力し、
REFERENCE_IDはsupabaseのProject Settings > Generalからでも確認できます。
実際にCLIより関数hello-world
を作成してみます。
supabase functions new hello-world
自動生成される関数はこの様な関数です。シンプルなDenoを用いた通信です。
// Setup type definitions for built-in Supabase Runtime APIs
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
console.log("Hello from Functions!")
Deno.serve(async (req) => {
const { name } = await req.json()
const data = {
message: `Hello ${name}!`,
}
return new Response(
JSON.stringify(data),
{ headers: { "Content-Type": "application/json" } },
)
})
Vscodeでの実装時、Denoのエラーが出る場合があります。
Vscodeの拡張機能より”Deno”をインストールをすることで解消します。
まずは、ローカル環境で実行してみます。
ローカルのsupabase開発環境を起動するコマンドを実行します。Dockerのコンテナが立ち上がり、認証IDなどが生成されます。supabaseで利用できるサービスすべてをローカル起動させるため、少々時間かかります。
supabase start
完了するとStudio URLや認証キーであるANON_KEYなどが表示されます。(この後API実行時利用します。)
もし再度表示したい場合は
supabase status
で同様の設定値を再度確認できます(ただしローカルのsupabase環境が起動している場合のみ)
次に起動したローカル環境で関数を実行するコマンドを実行します。ホットリロード機能付きです。嬉しいね。
supabase functions serve
これでローカル環境にEdgeFunctionを起動することができました!Postmanを用いて、早速POSTしてみましょう!
Headerに先ほど確認したANON_KEYをBearer {ANON_KEY}
として付与し、BodyにJSON形式で値を投げます。
Bodyに渡した値に”Hello”とついて返却されているのが確認できました!やった!!
認証をスキップしたい場合、以下のようなコマンドで実行することで、Headerに認証情報がなくても接続確認を行うことができます。開発時にはとても役立ちそうだ。。!(デプロイコマンドでも--no-verify-jwt
オプションは利用可能。)
supabase functions serve hello-world --no-verify-jwt
最後にローカル環境停止することをお忘れ無く、、!
supabase stop
次に、Supabaseクラウドへデプロイし、実行してみます。
supabase functions deploy hello-world --project-ref {REFERENCE_ID}
REFERENCE_IDを用いて、プロジェクトの紐付けを行います。REFERENCE_IDはsupabaseのProject Settings > Generalからでも確認できます。
deployを実施すると、supabaseダッシュボード上に関数hello-world
が作成されています。(反映には少々時間かかります。)
これでsupabase上にEdgeFunctionを起動することができました!ローカル同様、Postmanを用いて、早速POSTしてみましょう!
ヘッダーには以下情報を付与し、呼び出します。
'Authorization: Bearer {SUPABASE_ANON_KEY}'
'Content-Type: application/json'
ログはsupabaseダッシュボードよりEdgeFunction>hello-world>Logsより確認できます。
EdgeFunctionでからsupabaseのTBL処理をしてみる。
supabaseには他にもDatabaseの機能を存在します。
今回作成したEdgeFunctionからDB操作をしてみましょう。上記同様公式Docsを参考にしております。
先ほど作成したindex.ts
または、新しい関数としてファイルを新規作成し、index.ts
に以下関数を記述します。
今回は新しい関数としてselect-name
を作成しました。
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from "npm:@supabase/supabase-js"
console.log("Hello from Functions!")
const supabase = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!)
Deno.serve(async (req) => {
const { data,error } = await supabase.from(`message`).select(`name`).limit(1).single()
console.log(error)
const message = {
message: `Hello ${data?.name}!`,
}
return new Response(
JSON.stringify(message),
{ headers: { "Content-Type": "application/json" } },
)
})
今回環境変数値として、URLとANONKEYを指定しています。
EdgeFunctionではデフォルトの環境変数値が設定されており、そちらを利用します。
今回はSUPABASE_URL
とSUPABASE_ANON_KEY
を利用します。
詳細はSupabase Docs-Managing Environment Variables-
もしENVファイルにて、環境変数を定義する場合、ローカルDBへ接続する場合とクラウドDBへ接続する場合でそれぞれ異なります。
ローカルDBへの接続の場合、環境変数値は以下の様に定義します。
NEXT_PUBLIC_SUPABASE_URL = http://host.docker.internal:54321/
NEXT_PUBLIC_SUPABASE_ANON_KEY = {ローカル環境のAPIのANON_KEY}
URLはローカルサーバーへのURLとします。
(コマンドsupabase status
ではAPI URL: http://127.0.0.1:54321
と出るのですが、こちらの場合はTypeError: error sending request for url
エラーとなります。公式より同様質問があり、そちらを参照)
ANON_KEYはコマンドsupabase start
によるローカル実行後、supabase status
にて確認できます。
クラウドDBへの接続の場合、環境変数値は以下の様に定義します。
NEXT_PUBLIC_SUPABASE_URL = https://{REFERENCE_ID}.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY = {クラウド環境のAPIのANON_KEY}
REFERENCE_IDはSupabaseのProject Settings > Generalから確認できます。
ANON_KEYはSupabaseのAPI Settings > Project API Keys > anonから確認できます。
ENVファイルで環境変数値を定義する場合、頭にNEXT_PUBLIC_
の記載が必要です。
公式より同様質問があり、そちらを参照
まずはローカルDBでの接続を行ってみましょう。コマンドsupabase functions serve
にてローカル環境にEdgeFunctionを起動し、Postmanを用いて、POSTしてみます。
この様に呼び出せることはできましたが、Select結果はundefined
として返ってきました。
。。まだテーブル定義していないので当たり前ですね。
ここで便利な機能。ローカルホストでsupabaseStudioを利用することができます。
つまり、ローカル環境でのダッシュボードとしてGUIで視覚的にデータを作成したり、確認することができるのです。
(少し左側ドロワーの項目が違うのがわかりますね)
このTableEditorよりテーブルを作成してみましょう。
今回はTBL名を"message"とし、カラム"name"を追加してみます。
テーブルが作成できたら、データを追加してみます。
また同時にRLS(Row Level Security)も設定します。
RLSとはPostgreSQLでのテーブル内の行(Row)単位でのアクセスを制御する機能です。
今回は自動生成される、すべてのユーザーが閲覧のみ可能なRLSを作成し、付与します。
さて、これで再度、API呼び出ししてみると、、?
この様にDBから値を取ってきて、呼び出すことができる様になりました!
さらにさらに、supabaseへデプロイをしてみると、、?
無事にDBから値を取得し、APIで受け取ることができました!
Terraformで環境を作成してみる
次にIaCツールの1つであるTerraformを用いて、supabase環境を作成してみようと思います。つまり先ほどまでsupabaseのダッシュボードからポチポチ作成していたProjectなどなど、、インフラの構成をソースコードとして管理することができるのです。
参考:Supabase DOCS -Terraform-
まずはterraformのインストールから始めます。
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
参考:Terraform公式 Install Terraform
brew でインストールの方法について
頭ごなしにコマンドbrew install terraform
を叩かない様に!現在こちら非推奨コマンドです。
現在推奨はtap
で新しいリポジトリを作成し、そこにインストールする方式をとっています。
参照;【最新Mac対応】M1、M2、M3チップでTerraformをわずか3分でインストール!
さて、実際にTerraformを使ったsupabaseのセットアップをしていきましょう。
まずProviderの設定を行います。
Providerとは、Terraformと接続するクラウドサービスやSaaSと連携するためのプラグインのことです。ここではSupaBaseを指します。
以下ファイルを作成します。
terraform {
required_providers {
supabase = {
source = "supabase/supabase"
version = "~> 1.0"
}
}
}
provider "supabase" {
access_token = file("${path.cwd}/access-token")
}
supabaseへアクセスできる様にaccess-token
が必要となります。
ダッシュボードのAccount>Access TokensにてGenerate new token
ボタンより、新しいアクセストークンを取得し、保存します。一度しか表示されないので、コピーしてローカルのaccess-tokenファイルへ保存します。
次にResourcesの設定を行います。
Resourcesとは、インフラ構成を定義を記述するものです。ここではsupabaseに新しくプロジェクトを作成するという構成を定義します。
以下のファイルを作成します。
# Create a project resource
resource "supabase_project" "production" {
organization_id = {"組織ID"}
name = {"作成したいプロジェクト名:ex,tf-example"}
database_password = {"DBのパスワード"}
region = {"作成するリージョン:ex,ap-southeast-1"}
lifecycle {
ignore_changes = [database_password]
}
}
organization_id
はsupabaseのダッシュボードにて、作成したOrganizationのGeneral>General settings>Organization slugより確認できます。
これを以下Terraformコマンドで初期化+実行してみると、、?
# 初期化
terraform -chdir=module init
# 実行
terraform -chdir=module apply
ダッシュボードを開いてみると、新しいプロジェクトが立ち上がっているではありませんか、、!
新しくTerraformで作成したプロジェクトについては既存プロジェクトの参照IDと紐づけることによって、管理可能となります。
以下の様にプロジェクトIDを定義する変数を追加し、紐づけられる様修正します。
# ~~追加~~
# Define a linked project variable as user input
variable "linked_project" {
type = string
}
import {
to = supabase_project.production
id = var.linked_project
}
# ~~以降そのまま~~
# Create a project resource
resource "supabase_project" "production" {
organization_id = {"組織ID"}
name = {"作成したいプロジェクト名:ex,tf-example"}
database_password = {"DBのパスワード"}
region = {"作成するリージョン:ex,ap-southeast-1"}
lifecycle {
ignore_changes = [database_password]
}
}
TerraformのVariablesは環境変数値など変更できるパラメータを指します。
この状態でapplyコマンドを実行すると、
この様にコマンド実行ごとにプロジェクトIDを入力し、実行が可能となります。
また、実行ごとに入力するのも億劫なので、ファイルに別途定義を記載しておけば、そこから値を引っ張ってくることも可能です。
linked_project = {"プロジェクトID"}
まとめ
今回、EdgeFunctionを通じ、さまざまなsupabaseの機能を利用することができました。思ったより簡単に利用できますし、ローカルでもGUIで操作できたりするのも良いところです。また今回初めてDenoというランタイムに触れましたが、そちらも簡単に利用できたのも良かったと思います。しかしsupabaseはそれでもまだまだ利用しきれていない機能が盛りだくさんなので、引き続き利用してみたいと思います。
参考
コマンド苦手な私が、大変助かったCLIコマンド一覧を最後に参照させていただきます。今後の自分自身が利用するためのメモがわりです。