◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-03-28上級

Rork Max × Supabase Edge Functions & Row Level Security — セキュアな API 設計

Rork Max アプリで Supabase Edge Functions と Row Level Security(RLS)を活用し、セキュアでスケーラブルな API を設計・実装するための上級ガイド。認可パターンから本番運用まで網羅します。

Rork Max236Supabase37Edge FunctionsRow Level SecurityAPI設計セキュリティ14バックエンド11

✦ プレミアム記事

取り組みの背景 — なぜ Edge Functions × RLS が重要なのか

Rork Max でアプリを開発していると、クライアントサイドだけでは処理しきれないロジックに直面する場面が出てきます。外部 API との連携、決済処理、複雑なデータ集計、メール送信——こうしたサーバーサイドの処理を安全かつ効率的に実装するのが Supabase Edge Functions です。

一方、データベースのアクセス制御において「誰がどのデータを読み書きできるか」を厳密に管理するのが Row Level Security(RLS) です。RLS はデータベースレイヤーで動作するため、クライアントから直接 Supabase にアクセスされても不正なデータ参照を防ぐことができます。

この2つを組み合わせることで、Rork Max アプリのバックエンドは「軽量でありながら堅牢」な構成になります。ここで扱うのはEdge Functions と RLS を活用したセキュアな API 設計の全体像を、実装コード付きで解説します。

対象読者は、Rork Max で本格的なアプリをリリースしたい中上級者です。基本的な Supabase の操作(認証・CRUD)については Rork × Supabase 認証&リアルタイム機能実装ガイド で解説していますので、そちらを先にご覧ください。

Supabase Edge Functions の基本アーキテクチャ

Edge Functions とは

Supabase Edge Functions は、Deno ランタイム上で動作するサーバーレス関数です。Supabase のインフラストラクチャ内で実行されるため、データベースとの接続が高速で、コールドスタートも最小限に抑えられています。

主な特徴は以下の通りです。

  • Deno ランタイム: TypeScript をネイティブサポートし、セキュアなサンドボックス環境で実行される
  • グローバルエッジ配信: ユーザーに近いリージョンから応答するため低レイテンシ
  • Supabase クライアント組み込み: supabase-js が環境内で利用可能
  • シークレット管理: 環境変数として API キーやトークンを安全に保存

Edge Functions のディレクトリ構造

supabase/
├── functions/
│   ├── process-payment/
│   │   └── index.ts        # 決済処理
│   ├── send-notification/
│   │   └── index.ts        # プッシュ通知送信
│   ├── aggregate-analytics/
│   │   └── index.ts        # 分析データ集計
│   └── _shared/
│       ├── cors.ts          # CORS ヘルパー
│       ├── auth.ts          # 認証ヘルパー
│       └── response.ts      # レスポンスヘルパー
└── config.toml

_shared/ ディレクトリに共通ユーティリティを配置することで、各 Edge Function のコードを DRY(Don't Repeat Yourself)に保てます。

最小構成の Edge Function

以下は、認証済みユーザーのプロフィールを返すシンプルな Edge Function の例です。

// supabase/functions/get-profile/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";
 
// CORS ヘッダー定義
const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers":
    "authorization, x-client-info, apikey, content-type",
};
 
serve(async (req: Request) => {
  // preflight リクエスト対応
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }
 
  try {
    // リクエストヘッダーから JWT を取得
    const authHeader = req.headers.get("Authorization");
    if (!authHeader) {
      return new Response(
        JSON.stringify({ error: "認証が必要です" }),
        { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }
 
    // Supabase クライアントを認証済みユーザーとして初期化
    const supabase = createClient(
      Deno.env.get("SUPABASE_URL") ?? "",
      Deno.env.get("SUPABASE_ANON_KEY") ?? "",
      { global: { headers: { Authorization: authHeader } } }
    );
 
    // 認証済みユーザーの情報を取得
    const { data: { user }, error: userError } = await supabase.auth.getUser();
    if (userError || !user) {
      return new Response(
        JSON.stringify({ error: "無効なトークンです" }),
        { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }
 
    // RLS が適用された状態でプロフィールを取得
    const { data: profile, error } = await supabase
      .from("profiles")
      .select("*")
      .eq("id", user.id)
      .single();
 
    if (error) throw error;
 
    return new Response(
      JSON.stringify({ profile }),
      { status: 200, headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  } catch (err) {
    return new Response(
      JSON.stringify({ error: err.message }),
      { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  }
});
// 期待する出力例:
// { "profile": { "id": "uuid-xxx", "display_name": "Masaki", "avatar_url": "https://..." } }

このコードのポイントは、Authorization ヘッダーを Supabase クライアントに渡すことで、RLS ポリシーがユーザーコンテキストで評価される点です。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦Supabase Edge Functions の設計パターンと Rork Max からの呼び出し方を体系的に理解できる
✦Row Level Security(RLS)を使ったマルチテナント対応の認可設計を実装できる
✦本番環境での Edge Functions のデバッグ・パフォーマンス最適化・監視手法を習得できる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ 開発ツール2026-10-13
リリース前に、書き出した Expo バンドルの中から自分の鍵を探してみる
ソースに鍵がなくても、出来上がったアプリの中に鍵が残ることがあります。Expo SDK 57 で実際に expo export を実行し、バンドルの中身を grep と 60 行ほどの Node スクリプトで調べて、見つかる鍵と見つからない鍵の違いを確かめました。
⬡ 開発ツール2026-07-18
文字サイズ最大とドイツ語で、生成された画面は静かに詰まる — Rork Max の SwiftUI にレイアウト耐性の検証を通した記録
Rork Max が生成した SwiftUI 画面を疑似ローカライズと最大文字サイズに通し、どこから詰まるかを機械的に洗い出した記録です。ViewThatFits・ScaledMetric・layoutPriority の使いどころと、再生成のたびに回帰を捕まえるスナップショット検証を、実際の数値とともにまとめました。
⬡ 開発ツール2026-05-17
Rork Max の SwiftUI 機能を壁紙アプリ開発で検証した結果 — 実際に動いた機能と手を入れた機能
運用中の壁紙アプリの本番コードを基準に、Rork Max の SwiftUI ネイティブ生成を検証しました。そのまま使えた機能、手を入れた機能、生成を諦めた機能を、動くコードと実機での計測値とともにお伝えします。