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について

Posted at

Supabaseとは

SupabaseとはBackend機能を簡単に使用できるBackend as a Service(BaaS/バース)プラットフォーム。
主に以下の機能を提供します。

機能名 説明
Database フルマネージドなPostgreSQLを提供し、RowLevelSecurityを備えたREST / GraphQL APIを自動生成する。アプリ側から安全にデータを読み書きできる。
Auth 一連のIDプロバイダーとAPIを通じて、プロジェクトへのメール・パスワード・パスワードレス・OAuth・モバイルログインを追加および管理することが可能。
Storage 行レベルのセキュリティアクセスポリシーを使用してPostgresデータベースと完全に統合され、大容量ファイルの保存・整理・交換・提供が可能。
Edge Functions グローバルに分散されたサーバー側関数により、ユーザーに最も近い場所でコードを実行し、レイテンシを最小限に抑えることが可能。
Realtime データベースの変更をリッスンしたり、クライアント間でユーザーの状態を保存・同期したり、チャネルにサブスクライブしているクライアントにデータをブロードキャストすることが可能。

Supabase EdgeFunction

Supabase EdgeFunctionは、Denoランタイム上で動作するTypeScript/JavaScriptベースのサーバーレス関数です。

AWS LambdaやCloudflare Workersのように、サーバーを立てずにHTTPリクエストで実行できる関数をデプロイ可能です。

仕組み

  • リクエストがエッジゲートウェイ(リレー)に入ると、ゲートウェイはトラフィックをルーティング、認証ヘッダー/JWT検証を処理し、ルーティング/トラフィックルールを適用する。
  • 認証とポリシーが適用される。ゲートウェイは、コードを実行する前にSupabase JWTを検証、レート制限を適用し、セキュリティチェックを集中管理できる。
  • エッジランタイムが関数を実行する。関数は、ユーザーに最も近い地域に分散されたエッジランタイムノードで実行されるため、レイテンシが最小に抑えられる。
  • 統合とデータアクセス-関数は一般的にSupabase API(Auth,Postgres,Storage)または、サードパーティAPIを呼び出す。
  • 可観測性とログ-呼び出しにより、ダッシュボードまたはダウンストリームモニタリング(Sentryなど)で調べることができるログとメトリックスが生成される。
  • 応答はゲートウェイ経由で返される。ゲートウェイは応答をクライアントに転送し、要求のメタデータを記録する。

EdgeFunctionを使用する場合

  • 低レイテンシが必要な認証済みまたはパブリックHTTPエンドポイント
  • Webhookレシーバー(Stripe,Githubなど)
  • オンデマンドの画像またはOpenGraphの生成
  • 小規模なAI推論タスクまたは外部LLM APIへの呼び出しのオーケストレーション
  • トランザクションメールの送信
  • Slack,Discordなどのメッセージングボットの構築

実装例

画像をStorageバケットにアップロードすると、自動でその情報を Postgres のテーブルに保存する仕組みを実装します。

構成イメージ:

  1. ユーザーが画像をimagesバケットにアップロード
  2. storage.objectsテーブルへのINSERTをきっかけにDatabase Webhookが発火
  3. Webhook → EdgeFunction store-image-meta を HTTP POST
  4. EgeFunction内:
    • Webhook のペイロードから bucket_id, name, path_tokens などを取得
    • public.image_files テーブルに INSERT

準備

Supabase CLIの構築

# Supabase CLIのインストール
brew install supabase/tap/supabase

# プロジェクト初期化(未実施の場合)
supabase init

# 関数を作成
supabase functions new store-image-meta

# TypeScriptの方を作成(任意)
supabase gen types typescript \
  --project-id your-project-ref \
  --schema storage,public \
  > supabase/functions/store-image-meta/types.ts

実行すると、以下の構成が作成される

supabase/
  functions/
    store-image-meta/
      index.ts
      deno.json
      types.ts

Storageバケットとテーブルを用意する

Storageバケット imagesを作成

Supabase Dashboardから:

  • Storage→「new bucket」
    • Bucket name:images

スクリーンショット 2025-11-05 194341.png

スクリーンショット 2025-11-05 194419.png

画像メタ情報を保存するテーブルを作成

SQL Editerから:
以下のSQLをペースト→Run CTRL

  • テーブル名:image_files
    • カラム:
      • id:uuid (storage.objects.idを参照する外部キー)
      • bucket_id(どのバケットか)
      • path(パス文字列)
      • name(ファイル名)
      • uploaded_at
create table public.image_files (
  id uuid primary key references storage.objects(id) on delete cascade,
  bucket_id text not null,
  path text not null,
  name text not null,
  uploaded_at timestamptz not null default now()
);

スクリーンショット 2025-11-08 050404.png

スクリーンショット 2025-11-08 050447.png

EdgeFunctionの実装

// supabase/functions/store-image-meta/index.ts
import { serve } from "https://deno.land/std@0.177.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

// storage.objects の1行をざっくり表す型
type StorageObjectRow = {
  id: string;
  bucket_id: string;
  name: string;
  path_tokens: string[] | null;
};

// Database Webhook から飛んでくるペイロード
type WebhookPayload = {
  type: "INSERT" | "UPDATE" | "DELETE";
  table: string;
  schema: string;
  record: StorageObjectRow;
  old_record: StorageObjectRow | null;
};

const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? "";
const SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "";

console.log("[init] SUPABASE_URL set:", !!SUPABASE_URL);
console.log("[init] SERVICE_ROLE_KEY set:", !!SERVICE_ROLE_KEY);

const supabaseAdmin = createClient(SUPABASE_URL, SERVICE_ROLE_KEY);

serve(async (req) => {
  try {
    const payload = (await req.json()) as WebhookPayload;
    const record = payload.record;

    // INSERT 以外はスキップ(UPDATE/DELETE が飛んでくる可能性に備えて)
    if (payload.type !== "INSERT") {
      console.log("[hook] skip type:", payload.type);
      return new Response("skip", { status: 200 });
    }

    const path =
      (record.path_tokens && record.path_tokens.join("/")) || record.name;

    console.log("[hook] new object:", {
      id: record.id,
      bucket_id: record.bucket_id,
      path,
      name: record.name,
    });

    // image_files にメタ情報を保存
    const { error } = await supabaseAdmin
      .from("image_files")
      .insert({
        id: record.id,
        bucket_id: record.bucket_id,
        path,
        name: record.name,
      });

    if (error) {
      console.error("[hook] insert error:", error);
      return new Response(
        JSON.stringify({ error: error.message }),
        {
          status: 500,
          headers: { "Content-Type": "application/json" },
        },
      );
    }

    console.log("[hook] insert success");
    return new Response("ok", { status: 200 });
  } catch (err) {
    console.error("[hook] unhandled error:", err);
    return new Response("Internal Server Error", { status: 500 });
  }
});

必要な環境変数を設定

EdgeFunctionの実行環境に、以下の環境変数を設定:

  • SUPABASE_URL:プロジェクトURL(デプロイ時に自動で入るので通常は明示設定不要)。
  • SUPABASE_SERVICE_ROLE_KEY:ServiceRoleキー(デプロイ時に自動で入るので通常は明示設定不要)。

Supabase CLIから設定する場合は:

supabase secrets set SUPABASE_SERVICE_ROLE_KEY="your_service_role_key"

関数をデプロイ

Supabaseプロジェクトとローカルを紐づけたうえで、EdgeFunctionをデプロイする

# プロジェクトとリンク(まだの場合)
supabase link --project-ref your-project-ref

# 関数をデプロイ
supabase functions deploy store-image-meta

DatabaseWebhookで自動実行

Dashboardから:

  • 「Database」 → 「Webhooks」
    • enable webhooksをONに設定
  • 「Create a new hook」
    • Table: storage.objects
    • Event: INSERT(新しい画像がアップロードされたとき)
    • Webhook type: Edge Function
    • Function name: store-image-meta

スクリーンショット 2025-11-08 042049.png

スクリーンショット 2025-11-08 042217.png

スクリーンショット 2025-11-08 051154.png

こうしておくと、Storage に画像がアップロードされるたびに Edge Function が自動実行されます。

動作確認

  1. Dashboardから:
  • 「Storage」 → 「images」バケットに適当な画像をアップロード
  1. トリガーに Webhook → EdgeFunction store-image-meta が呼ばれる
  2. Edge Function が public.image_files にメタデータをコピー
  3. 「Table Editor」 → 「image_files」テーブルにレコードが存在するかを確認

スクリーンショット 2025-11-08 050823.png

スクリーンショット 2025-11-08 050813.png

参考元

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?