0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SupabaseのEdgeFunctionやDB関連をローカル環境で開発するときのTips

Last updated at Posted at 2025-04-25

EdgeFunction関連

ローカル開発では再起動と関数実行をひたすら繰り返すので、コマンドライン主体で修正サイクルを回すと早いです。

起動

起動

supabase functions serve

Background起動

supabase functions serve &

ログを書き出しながらバックグラウンド起動

supabase functions serve > functions.log  2>&1 &

バックグラウンドで起動したときの終了方法(fg + Ctrl-C以外)

pkill -f "supabase functions serve"

関数名を指定して起動。ただ今のところ関数をすべて起動してもそれほど重くなさそうなので一括で起動することが多いです。

supabase function serve somefunction

jwt認証を無効化して起動

supabase functions serve --no-verify-jwt

関数ごとにjwt認証無効など

config.tomlに関数ごとの設定の既定値を書いておけます。

config.toml
[functions.somefunction]
verify_jwt = false

こうすると supabase function serve したり supabase function deploy したときに関数ごとに設定を個別に行うことができます。

ポート番号変更

これも設定。複数プロジェクトをローカルで同時に動かすときには10ずつずらしています。

config.toml
[api]
enabled = true
# Port to use for the API URL.
port = 54411

アクセストークンを取得(jq利用)

ローカルでは 「--no-verify-jwt すれば開発が捗る」とはいえ、RLSが有効になっているテーブルに対してEdgeFunctionを動作させる場合にはユーザーの認証情報を引き継いで検証しながら開発をする必要があります。

まずは存在するユーザーでJWTトークンを取得。

ポート番号を変えたりしているので supabase status で確認しながら取得。
認証するユーザーとパスワードは変数で定義。

USER=user1@kater.jp PASSWORD=password123
curl -s -X POST $(supabase status --output json | jq -r '.API_URL')'/auth/v1/token?grant_type=password' \
  -H "apikey: $(supabase status --output json | jq -r '.ANON_KEY')" \
  -H "Content-Type: application/json" \
  -d '{"email":"'${USER}'","password":"'${PASSWORD}'"}' | jq -r '.access_token'

JWTを持ってEgdeFunctionを叩く

curl -H "Authorization: Bearer $ACCESS_TOKEN" $(supabase status --output json | jq -r '.API_URL')/functions/v1/somefunction

まとめて実行

USER=user1@kater.jp PASSWORD=password123
ACCCESS_TOKEN=$(curl -s -X POST $(supabase status --output json | jq -r '.API_URL')'/auth/v1/token?grant_type=password' \
  -H "apikey: $(supabase status --output json | jq -r '.ANON_KEY')" \
  -H "Content-Type: application/json" \
  -d '{"email":"'${USER}'","password":"'${PASSWORD}'"}' | jq -r '.access_token')

curl -H "Authorization: Bearer $ACCESS_TOKEN" $(supabase status --output json | jq -r '.API_URL')/functions/v1/somefunction

関数の再起動とまとめて実行

# 再起動
pkill -f "supabase functions serve" ; supabase functions serve > supabase/functions.log 2>&1 & sleep 2

# JWTの取得
USER=user1@kater.jp PASSWORD=password123
ACCCESS_TOKEN=$(curl -s -X POST $(supabase status --output json | jq -r '.API_URL')'/auth/v1/token?grant_type=password' \
  -H "apikey: $(supabase status --output json | jq -r '.ANON_KEY')" \
  -H "Content-Type: application/json" \
  -d '{"email":"'${USER}'","password":"'${PASSWORD}'"}' | jq -r '.access_token')

# 関数を叩く
curl -H "Authorization: Bearer $ACCESS_TOKEN" $(supabase status --output json | jq -r '.API_URL')/functions/v1/somefunction

EdgeFunction内でユーザーをトークンのユーザに切り替え


    const supabaseClient = createClient(
      supabaseUrl ?? '', supabaseAnonKey ?? '',
      {
        global: {
          headers: { Authorization: 'Bearer ' + req.headers.get('Authorization') || '' },
        },
      }
    )

    // ユーザーをANONからJWTのユーザーにすげ替える
    const token = authHeader.replace('Bearer ', '')
    const { data: { user }, error: authError } = await supabaseClient.auth.getUser(token)

下記の公式の記事を見ていたんですがうまくいかず。

で、公式サンプル とかを見ると createClient のときの第三引数に global.headers を与える必要があるっぽくて、それを与えるとうまくいきました。

下記です。

createClient(
      supabaseUrl ?? '', supabaseAnonKey ?? '',
      {
        global: {
          headers: { Authorization: 'Bearer ' + req.headers.get('Authorization') || '' },
        },
      }
)

DenoじゃなくてNodeで検証

EdgeFunctionの起動すら面倒なときはまずNodeで検証して移植すると良いです。でもDeno特有の問題とかあるので注意が必要。

Nodeで検証するサンプルコードと検証コマンド
sample.ts

import { createClient } from '@supabase/supabase-js';

const SUPABASE_URL = 'http://127.0.0.1:54411';
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0';

async function main(jwt: string) {
  console.log('Received JWT:', jwt);

  // Supabaseクライアントの作成
  const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY,
    {
      global: {
        headers: { Authorization: 'Bearer ' + jwt },
      },
    }
  );

  try {
    // ユーザー認証
    // const { data: user, error: authError } = await supabase.auth.getUser(jwt)
    const { data: user, error: authError } = await supabase.auth.getUser(jwt);

    console.log('認証成功:', user?.user?.email);

    // 画像の取得
    const { data: imageData, error: imageError } = await supabase
      .from('images')
      .select('*')
      .eq('id', '0287da2f-4058-891c-787e-7d68a7346ee8')
      .single();

    if (imageError) {
      throw imageError;
    }

    if (!imageData) {
      console.log('画像が見つかりませんでした');
      return;
    }

    console.log('取得した画像データ:', imageData);

  } catch (error) {
    console.error('エラーが発生しました:', error);
  }
}

// JWTを引数として渡して実行
if (process.argv.length < 3) {
  console.error('使用方法: ts-node get_image2.ts <JWT>');
  process.exit(1);
}

main(process.argv[2]);
USER=user1@kater.jp PASSWORD=password123
ACCCESS_TOKEN=$(curl -s -X POST $(supabase status --output json | jq -r '.API_URL')'/auth/v1/token?grant_type=password' \
  -H "apikey: $(supabase status --output json | jq -r '.ANON_KEY')" \
  -H "Content-Type: application/json" \
  -d '{"email":"'${USER}'","password":"'${PASSWORD}'"}' | jq -r '.access_token')

# 関数実行
ts-node sample.ts $ACCESS_TOKEN

参考

DB関連

接続

psqlで接続。ポート番号とか変えてる事があるので supabase status を利用。

psql  "$(supabase status --output json | jq -r '.DB_URL')

db reset マイグレーションからの再適応

supabase db reset

シーディングのみやり直し

db reset だと時間がかかるので開発用のシードの調整を行う場合には truncate -> シード読み込み で時間短縮。

truncate_all_data_atpublic_schema.sql
DO $$
DECLARE
  r RECORD;
BEGIN
  FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'public') LOOP
    EXECUTE 'TRUNCATE TABLE public.' || quote_ident(r.tablename) || ' CASCADE';
  END LOOP;
END $$;

複数のプロジェクトで使うのでGistに上げておきました。

このスクリプトを使ってDBのクリア。

curl -s https://gist.githubusercontent.com/yousan/a29149ffe7ba7459011a61cb9710674b/raw/06d03f4fd4a9593a719a4acffff92545ee6e0fab/truncate_all_data_at_public_schema.sql | psql "$(supabase status --output json | jq -r '.DB_URL')"
psql  "$(supabase status --output json | jq -r '.DB_URL')" < supabase/seed.sql ;
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?