FastAPI × SupabaseでSNSデータを安全に保存する構成を作った話
FastAPI × SupabaseでSNSデータを安全に保存する構成を作った話
Vue × FastAPIでSNSダッシュボードを作っていたとき、ふとこんな疑問が。
「あれ、このデータ、アプリ閉じたら全部消えるんじゃ……?」
最初はローカルメモリで管理していたSNSのKPIデータですが、蓄積してこそ意味がある!と思い立ち、Supabase × FastAPIでの永続化に挑戦してみました。
この記事では、
-
SupabaseとFastAPIの接続方法
-
テーブル設計とRLS(Row Level Security)対応
-
JWTとの連携ポイント
つまずいた実装トラブル
をまとめて紹介します。
なぜSupabaseを選んだのか
FirebaseよりもSQLに強く、PostgreSQL互換
RLS(Row Level Security)でユーザーごとのアクセス制限が簡単
APIキーでの連携がFastAPIと相性◎
GitHubログインなどのAuthも使える
データ構成と目的(テーブル紹介)
Supabaseで作成したテーブルは以下の通り:
| カラム名 | 型 | 説明 |
|---|---|---|
| id | UUID | 主キー、自動生成 |
| date | DATE | 記録日 |
| INTEGER | Instagramフォロワー数などの指標 | |
| tiktok | INTEGER | TikTokの指標 |
| x | INTEGER | X(旧Twitter)の指標 |
| user_id | UUID | ユーザー識別用のID(JWTと連携) |
FastAPIとの接続実装(コード付き)
まずは .env に以下を追加:
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_KEY=your-anon-or-service-role-key
supabase_client.py
from supabase import create_client
import os
from dotenv import load_dotenv
load_dotenv()
url = os.getenv("SUPABASE_URL")
key = os.getenv("SUPABASE_KEY")
supabase = create_client(url, key)
metrics.py(POSTの例)
from fastapi import APIRouter, Depends
from supabase_client import supabase
from dependencies import get_current_user
from datetime import date
router = APIRouter()
@router.post("/metrics")
def add_metric(data: dict, user: dict = Depends(get_current_user)):
data["user_id"] = user["sub"] # JWTからユーザーID取得
data["date"] = str(date.today())
supabase.table("metrics").insert(data).execute()
return {"message": "Metric added"}
RLSの設定とハマりポイント
Supabaseのテーブル作成後、RLSをONにして以下のポリシーを追加:
CREATE POLICY "Allow logged-in users" ON metrics
FOR SELECT USING (auth.uid() = user_id);
よくあるハマりポイント:
supabase_key is required → .envが読み込まれていない or Keyの種類が違う(anon と service)
row violates policy → user_id を忘れている or JWTのsubと一致していない
おわりに
今までは「とりあえず見える化」で満足していたダッシュボードも、Supabaseで蓄積できるようになって初めて、「成長を追えるツール」に育ちました。
次回はこのデータを Vue + Chart.js でグラフ表示し、
より直感的なKPI分析ができるダッシュボードに進化させていく予定です💪
📦 完成したコードはこちら👇🔗 GitHub - TKNRFJK1208/kpi-dashboard
🙌 最後まで読んでいただきありがとうございます!
質問や感想はZennのコメントでもTwitterでもお待ちしてます〜!
Discussion