SuperAPI AI 工具集

supabase-sdk-patterns

编程与开发

查看项目

更新于 10-16 09:09

技能介绍

用途

这是一个关于 Supabase SDK 使用模式的技能,面向使用 @supabase/supabase-js v2 或 supabase-py 实现 Supabase 查询、认证、实时、存储或 RPC 调用的场景。其核心约定是:每次调用都返回 { data, error },绝不假设成功。

主要能力

提供以下生产模式:

  • 带 Database 泛型的类型安全单例客户端
  • 使用完整过滤链(eq、gt、in、ilike 等)的 CRUD 操作
  • insert-with-select 与 upsert(冲突处理)模式,可返回受影响行
  • 注册、登录、会话管理与状态监听的认证流程
  • 带行级过滤与清理的实时订阅
  • 存储上传/下载,私有 bucket 使用签名 URL
  • 查询模式的 Python 等价实现

前置条件

  • 已具备含 URL 与 anon key 的 Supabase 项目(服务端可使用 service role key)
  • 已安装 @supabase/supabase-js v2(TypeScript)或 supabase pip 包(Python)
  • TypeScript 项目:通过 supabase gen types typescript 生成数据库类型

使用方式

第一步:初始化带类型的单例客户端

创建一个客户端实例并复用,不要每次请求都调用 createClient —— 单例可保留认证会话与连接池。

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
import type { Database } from './database.types'

let supabase: ReturnType<typeof createClient<Database>>

export function getSupabase() {
  if (!supabase) {
    supabase = createClient<Database>(
      process.env.SUPABASE_URL!,
      process.env.SUPABASE_ANON_KEY!,
      {
        auth: { autoRefreshToken: true, persistSession: true },
        db: { schema: 'public' },
        global: { headers: { 'x-app-name': 'my-app' } },
      }
    )
  }
  return supabase
}

Python 等价写法:

from supabase import create_client, Client

_client: Client | None = None

def get_supabase() -> Client:
    global _client
    if _client is None:
        _client = create_client(
            os.environ["SUPABASE_URL"],
            os.environ["SUPABASE_ANON_KEY"],
        )
    return _client

第二步:查询、过滤与修改数据

解构 { data, error },在访问 data 之前先检查 error。在 .from(table).select(...) 上链式添加过滤条件;在 insert/upsert 后使用 .select().single() 返回受影响行。骨架示例:

const { data, error } = await getSupabase()
  .from('users')
  .select('id, name, email')
  .eq('active', true)
  .order('name')
  .limit(10)

if (error) throw error

完整的 CRUD 集合(insert-with-select、on conflict 的 upsert、update、delete、RPC)、完整的 12 个过滤条件参考表以及 Python 等价写法,请参见 queries and filters 部分。

第三步:认证、实时与存储

认证、实时频道与存储都遵循相同的 { data, error } 约定。认证暴露 signUp / signInWithPassword / getSession / onAuthStateChange;实时在频道上订阅 postgres_changes,并需要 removeChannel 清理;存储按 bucket 执行 upload / download / getPublicUrl / createSignedUrl。每个主题的完整代码讲解请参见 auth、realtime 和 storage 部分。

输出

应用这些模式可获得:

  • 带 Database 泛型的类型安全单例客户端
  • 使用完整过滤链(eq、gt、in、ilike 等)的 CRUD 操作
  • 返回受影响行的 insert-with-select 与 upsert 模式
  • 注册、登录、会话管理与状态监听的认证流程
  • 带行级过滤与清理的实时订阅
  • 私有 bucket 使用签名 URL 的存储上传/下载
  • 查询模式的 Python 等价实现

错误处理

每个 Supabase 调用都返回 { data, error },绝不可跳过错误检查。

const { data, error } = await getSupabase().from('users').select('*')

if (error) {
  // error 是 PostgrestError,包含以下字段:
  //   error.message  — 人类可读的描述
  //   error.code     — Postgres 错误码(例如 '23505')
  //   error.details  — 附加上下文
  //   error.hint     — Postgres 给出的修复建议
  console.error(`Query failed [${error.code}]: ${error.message}`)
  throw error
}

// 只有在错误检查通过后,使用 data 才是安全的

错误码对照:

错误码 含义 处理方式
PGRST116 未找到行(.single()) 返回 null 或 404,不要抛出
23505 唯一约束冲突(Postgres 重复键) 使用 .upsert() 或显示冲突错误
42501 RLS 策略违规(Postgres 权限不足) 检查认证状态与 RLS 策略
PGRST000 连接错误 使用指数退避重试
42P01 表不存在 核对表名并运行迁移
23503 外键违规 先确保被引用的行存在
42703 列不存在 检查列名,重新生成类型

示例

推荐的生产形态是一层类型安全的服务层,包装客户端,使调用方无需接触原始查询;再加一个分页辅助函数,在一次往返中返回一页行和总计数。两个可直接复制使用的完整实现见 service patterns 部分。

资源

  • Supabase JS Client Reference
  • TypeScript Support & Type Generation
  • Supabase Auth Reference
  • Realtime Guide
  • Storage Guide
  • Python Client Reference

后续步骤

数据库 schema 设计参见 supabase-schema-from-requirements;带 RLS 策略的认证深入讲解参见 supabase-install-auth;实时架构模式参见 supabase-auth-storage-realtime-core。