2026-03-173 phút đọcVI
- 0.Chuỗi bài: Supabase từ setup đến deploy
- 1.Tổng quan Supabase
- 2.Project setup, CLI và biến môi trường
- 3.Thiết kế schema Postgres và bảng
- 4.Migrations: viết và áp dụng
- 5.Auth: JWT, session và tích hợp backend
- 6.Prisma + Supabase: kết nối và đồng bộ schema
- 7.Row Level Security (RLS) và policy
- 8.API: PostgREST, custom API và khi nào dùng gì(bài này)
- 9.Realtime và Edge Functions
- 10.Deploy, CI/CD và multi-project
API: PostgREST vs custom API and when to use which
Introduction
Supabase provides PostgREST: a REST API generated from your Postgres schema (CRUD by table, filter, sort, pagination). Sometimes you need complex logic, multiple tables, webhooks or external integration → then you write a custom API (NestJS, Express, FastAPI) that calls Supabase (DB or PostgREST). This post compares PostgREST and custom API, when to use which, and how to keep a clear REST contract.
Goal: Choose the right channel (PostgREST vs your own backend) and design a consistent API (contract, versioning if needed).
Features
PostgREST
- Automatic: Each table (e.g.
conversations) → resourceGET/POST/PATCH/DELETE /rest/v1/conversations. Filter via query (?id=eq.xxx), select columns, order, limit/offset. HeaderAuthorization: Bearer <jwt>; RLS applies. - Pros: No need to write endpoints; schema change (new column) → API gets it. Good for simple CRUD and frontend calling directly.
- Limits: Complex logic (multi-step, transaction, external services) does not live in PostgREST; you need a separate backend or Edge Function.
Custom API
- Your backend: NestJS, Express, FastAPI, etc. on server/Vercel/Lambda. Can use Supabase client (service role) to read/write DB or call PostgREST; or Prisma/raw SQL.
- Use when: Multi-step workflows, transactions, webhooks, sending email, calling third-party APIs; or when you want to hide schema (API contract different from table structure).
Workflow / Process
- Định hình use case: Chỉ CRUD đơn giản, frontend có JWT → dùng PostgREST. Có logic phức tạp hoặc cần ẩn DB → thiết kế endpoint custom.
- Contract rõ ràng: Dù PostgREST hay custom, định nghĩa “client gọi gì, nhận gì” (method, path, body, response). Custom API nên có OpenAPI/Swagger hoặc doc tĩnh.
- Phân vai: PostgREST = truy cập trực tiếp tới bảng (đã RLS); custom API = orchestration, gọi Supabase bên trong. Tránh trùng lặp endpoint cùng một nghiệp vụ (chọn một kênh).
- Auth: Cả hai đều nhận JWT; custom API verify JWT (bài 5) rồi gọi Supabase với JWT (pass-through) hoặc service role (khi cần bypass RLS có kiểm soát).
Quy ước: Tách rõ “API public” (frontend gọi) và “data layer” (Supabase); custom API là lớp trên data layer, không lộ chi tiết schema nếu không cần.
Sample code
Call PostgREST from frontend
const { data } = await supabase
.from('conversations')
.select('id, title, created_at')
.eq('user_id', userId)
.order('updated_at', { ascending: false })
.limit(20);Custom API (Express): aggregate endpoint
// GET /api/me/conversations-summary
app.get('/api/me/conversations-summary', async (req, res) => {
const userId = getUserIdFromRequest(req);
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
const { data, error } = await supabaseAdmin
.from('conversations')
.select('id, title, updated_at')
.eq('user_id', userId)
.order('updated_at', { ascending: false })
.limit(20);
if (error) return res.status(500).json({ error: error.message });
res.json(data);
});supabaseAdmin dùng service role; hoặc dùng JWT của user (pass-through) để RLS vẫn áp dụng.
Apply in your architecture
- API contract: PostgREST contract = schema + RLS; custom API contract = endpoint + request/response. Keep consistent (names, JSON format, error codes) so clients and team can integrate easily.
- Tách biệt consumer và data: Frontend có thể gọi PostgREST trực tiếp (đơn giản) hoặc chỉ gọi custom API (ẩn schema). Backend custom đóng vai “orchestrator” khi cần, không nhân bản toàn bộ CRUD đã có sẵn ở PostgREST.
- Một nguồn sự thật: Dữ liệu vẫn nằm trong Supabase; PostgREST và custom API cùng đọc/ghi một DB, tránh đồng bộ hai nguồn.
Kết
PostgREST đủ cho CRUD và truy vấn đơn giản; custom API dùng khi có logic phức tạp hoặc cần ẩn schema. Bài tiếp sẽ nói Realtime và Edge Functions.
Bài tiếp: 09 — Realtime và Edge Functions
Đọc thêm: Supabase — PostgREST API