Supabase Edge Functions を試す(Deno)

Supabase Edge Functions を試すにあたって、RDBが PostgreSQLだということについての準備を終えました。
今回は、Supabase Edge Functions 本体を試します。

参考

環境構築

前提

supabase にログイン、プロジェクトを作成しておき、ここでは first-project としました。
この時、プロジェクトのホーム画面で Project Configuration という項目でURLが記載されています。
https://hogehogehoge.supabase.co のようになっており、これの hogehogehoge 部分は後で使うので控えておきます。

また、Project API keys の、anon public と書かれたところも、後ほど使用します。

CLI ツール導入

supabase のデプロイをするためにはCLIの導入が必要な様子。
CLIだけ導入されているdocker-imageはなさそうだったので、以下のDockerfileを自作。
(別にdenoのイメージをベースにする必要は無いんですが、追々楽そうだったので。)

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
FROM denoland/deno:1.20.4

RUN apt-get update && apt-get install -y wget &&\
wget https://github.com/supabase/cli/releases/download/v0.24.5/supabase_0.24.5_linux_amd64.deb &&\
dpkg -i supabase_0.24.5_linux_amd64.deb

RUN mkdir /usr/src/app
WORKDIR /usr/src/app


EXPOSE 8080
1
2
3
4
5
6
7
8
9
10
11
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec app bash

$ which supabase
/usr/local/bin/supabase

$ /usr/src/app# supabase -h
Supabase CLI 0.24.5

# 以下コマンドが並ぶ

Function を作成/デプロイ

supabase - Edge Functions に倣い、Function を作成してみます。

以下コマンドで作成します。

1
2
3
4
5
6
7
8
9
$ supabase functions new first-function
$ tree
.
|-- docker-compose.yml
|-- dockerfile
`-- supabase
`-- functions
`-- first-function
`-- index.ts

コマンド実行すると、カレントディレクトリから supabase が掘られます。

index.ts の中身は次の通り。

supabase/functions/first-function/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.

import { serve } from "https://deno.land/std@0.131.0/http/server.ts"

console.log("Hello from Functions!")

serve(async (req) => {
const { name } = await req.json()
const data = {
message: `Hello ${name}!`,
}

return new Response(
JSON.stringify(data),
{ headers: { "Content-Type": "application/json" } },
)
})

// To invoke:
// curl -i --location --request POST 'http://localhost:54321/functions/v1/' \
// --header 'Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXX' \
// --header 'Content-Type: application/json' \
// --data '{"name":"Functions"}'

(セキュアな認証情報がコメントに載っているのでマスクしています。)

それではデプロイしてみます。

1
2
3
4
5
6
7
8
9
# 一旦ログイン
$ supabase login
# => You can generate an access token from https://app.supabase.io/account/tokens.
# Enter your access token: https://app.supabase.io/account/tokens で発行したトークンを入力

$ supabase functions deploy first-function --project-ref [プロジェクトのID(ここでは、hogehogehoge)]
# => Bundling first-function
# Deployed Function first-function on project hogehogehoge
# You can inspect your deployment in the Dashboard: https://app.supabase.io/project/hogehogehoge/functions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx/details

実行結果に記載されたURLへアクセスすると、作成されたFunctionのページに飛びます。
実行方法の記載を見ると次のようになっています。

1
curl -L -X POST 'https://hogehogehoge.functions.supabase.co/first-function' -H 'Authorization: Bearer [YOUR ANON KEY]' --data '{"name":"Functions"}' 

と書かれています。この、[YOUR ANON KEY] を埋めてやると良いようですが、管理画面のて時かなところには、記載がありません。
これはプロジェクトのホーム画面のProject API keysanon public の部分が該当するのでこの値で埋めて実行します。
実行結果は、次の通りです。

1
2
$ curl -L 'https://hogehogehoge.functions.supabase.co/first-function' -H 'Authorization: Bearer トークン文字列' --data '{"name":"Functions"}'
#=> {"message":"Hello Functions!"}

実装の通り、{"message":"Hello 2Functions!"} と返ってきます。

関数をデプロイできました。

supabase Edge Functions でデータベースを参照してみる

それでは引き続き、データベースへのアクセスを試みてみます。

テーブルの作成

supabase の管理画面を見ると、Table Editor というものがありました。
こちらで、テーブル作成を行うようなので、簡単なテーブルを作成してみます。
いくつかスキーマがあるようでしたが、今回は public を選択しました。

Items テーブルの作りは次の通りです。

カラム名 Type
id int8 デフォルト
created_ta timestamptz デフォルト
name varchar

画面はこんな感じ。

数秒で作成は終わりました。

管理画面からデータが追加できたので適当なデータを入れておきます。

アプリケーションを改修

サンプルを元に確認目的で雑に実装。

supabase/functions/first-function/index.ts(データベース接続改修)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { serve } from "https://deno.land/std@0.131.0/http/server.ts"
import { createClient } from 'https://esm.sh/@supabase/supabase-js@1.34.0'

export const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
)

serve(async (req) => {
const { data, error } = await supabaseClient.from('items').select()

return new Response(
JSON.stringify({items: data}),
{ headers: { "Content-Type": "application/json" } },
)
})

実行すると次のように結果が返ってきます。

1
2
$ curl -L 'https://hogehogehoge.functions.supabase.co/first-function' -H 'Authorization: Bearer トークン文字列'
#=> {"items":[{"id":1,"created_at":"2022-04-16T16:18:22+00:00","name":"装動1"},{"id":2,"created_at":"2022-04-16T16:18:50+00:00","name":"装動2"},{"id":3,"created_at":"2022-04-16T16:18:56+00:00","name":"装動3"}]}

専用クライアントで取れてしまうので、既に PostgreSQL の知識を要さないところがポイント。
(念のためやっておいたPostgreSQLの事前確認は何だったんだ。)

常に全件取得というのも面白くないので、データを絞ってみます。

データベースにアクセスしてデータを絞ってみる

where 句に相当する機能については、github - supabase/postgrest.js に記載がある。
結構な数があるので、supabase を使うなら必須で持っておくべき知識ではありそう。
今回は、eq だけ使用します。

supabase/functions/first-function/index.ts(データベース接続改修)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { createClient } from 'https://esm.sh/@supabase/supabase-js@^1.33.2'
import { serve } from "https://deno.land/std@0.131.0/http/server.ts"

export const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
)

serve(async (req) => {

const { id } = await req.json()
const { data, error } = await supabaseClient.from('items').select().eq('id', id)

return new Response(
JSON.stringify({items: data}),
{ headers: { "Content-Type": "application/json" } },
)
})

実行結果は次の通り。

1
2
3
4
5
6
7
8
$ curl -L 'https://hogehogehoge.functions.supabase.co/first-function' -H 'Authorization: Bearer トークン文字列' --data '{"id":1}'
#=> {"items":[{"id":1,"created_at":"2022-04-16T16:18:22+00:00","name":"装動1"}]}

$ curl -L 'https://hogehogehoge.functions.supabase.co/first-function' -H 'Authorization: Bearer トークン文字列' --data '{"id":2}'
#=> {"items":[{"id":2,"created_at":"2022-04-16T16:18:50+00:00","name":"装動2"}]}

$ curl -L 'https://hogehogehoge.functions.supabase.co/first-function' -H 'Authorization: Bearer トークン文字列' --data '{"id":4}'
#=> {"items":[]}

Supabase Edge Functions を試してみた。
今回は Supabase client を使って直接データベースへの接続をしてみたが、別途提供されている環境変数も使用することで、直接接続もできる様子。
データベースのパスワードは、環境変数で提供されていないようなので、これは独自に環境変数を定義して渡す必要がありそう。
環境変数の設定をドキュメントに従い行ってみたところ、動作が確認できなかったので継続確認します。

ではでは。