Dùng Hasura thay Supabase API: GraphQL Backend Từ PostgreSQL

17/05/2026 · P T P · Chung

Dùng Hasura thay thế Supabase API: tạo GraphQL backend từ PostgreSQL

Bạn có PostgreSQL tốt. Schema rõ. Dữ liệu thật. Nhưng API REST sinh tự động từ Supabase chưa đủ linh hoạt? Cần GraphQL, query lồng sâu, permission tinh hơn, subscription mạnh hơn, hoặc muốn backend API tách khỏi stack Supabase? Hasura là lựa chọn đáng xét.

Hasura không thay PostgreSQL. Hasura đứng trước PostgreSQL, đọc schema, sinh GraphQL API realtime gần như tức thì. Bảng thành query. Quan hệ thành nested object. Insert/update/delete thành mutation. Policy thành rule. Event thành webhook.

Nói ngắn: PostgreSQL là nguồn dữ liệu. Hasura là API engine.

Vì sao thay Supabase API bằng Hasura?

Supabase rất mạnh: database, auth, storage, edge functions, realtime, dashboard. Nhưng API mặc định của Supabase chủ yếu dựa trên PostgREST, tức REST API sinh từ PostgreSQL. Dùng tốt cho nhiều app CRUD. Nhưng khi app lớn hơn, vài điểm bắt đầu khó chịu.

Khi REST tự động chưa đủ

Ví dụ màn hình cần:

– thông tin user
– danh sách project
– mỗi project có task mới nhất
– mỗi task có assignee
– tổng số comment
– trạng thái quyền thao tác

Với REST, dễ sinh nhiều request hoặc endpoint RPC riêng. Với GraphQL, client gửi một query đúng shape dữ liệu cần:

query GetDashboard {
  users_by_pk(id: "user-1") {
    id
    name
    projects {
      id
      name
      tasks(limit: 5, order_by: { created_at: desc }) {
        id
        title
        assignee {
          id
          name
        }
        comments_aggregate {
          aggregate {
            count
          }
        }
      }
    }
  }
}

Client lấy đúng dữ liệu. Không thừa nhiều. Không thiếu. Ít round-trip.

Khi permission cần chi tiết

Hasura permission dựa trên role, session variable, row-level condition, column permission. Ví dụ role user chỉ thấy project mình tham gia:

{
  "members": {
    "user_id": {
      "_eq": "X-Hasura-User-Id"
    }
  }
}

Không cần viết controller. Không cần copy logic permission khắp API. Rule nằm gần data model.

Khi muốn realtime GraphQL

Hasura hỗ trợ subscription qua WebSocket. Ví dụ client subscribe task mới:

subscription WatchTasks {
  tasks(where: { status: { _eq: "open" } }) {
    id
    title
    created_at
  }
}

Dùng cho dashboard, notification, collaborative UI, admin panel.

Kiến trúc: Supabase làm database, Hasura làm API

Thay Supabase API không có nghĩa bỏ Supabase. Mô hình phổ biến:

Supabase PostgreSQL: lưu dữ liệu.
Supabase Auth: quản lý đăng nhập.
Hasura: sinh GraphQL API.
Frontend: gọi Hasura bằng JWT.
Webhook/Action/Event Trigger: xử lý business logic ngoài database.

Luồng cơ bản:

1. User đăng nhập qua Supabase Auth.
2. Frontend nhận JWT.
3. Frontend gọi Hasura GraphQL endpoint.
4. Hasura kiểm JWT, lấy claims như role, user id.
5. Hasura áp permission rồi query PostgreSQL.

Điểm quan trọng: JWT phải chứa claim Hasura hiểu, thường dạng:

{
  "https://hasura.io/jwt/claims": {
    "x-hasura-default-role": "user",
    "x-hasura-allowed-roles": ["user"],
    "x-hasura-user-id": "123"
  }
}

Với Supabase Auth, cần custom claims qua hook, trigger, hoặc service trung gian tuỳ kiến trúc. Nếu chưa muốn đụng JWT ngay, có thể bắt đầu bằng admin secret trong môi trường dev, rồi siết auth sau.

Cài Hasura nhanh với Docker

Tạo docker-compose.yml:

version: "3.6"
services:
  graphql-engine:
    image: hasura/graphql-engine:v2.44.0
    ports:
      - "8080:8080"
    environment:
      HASURA_GRAPHQL_DATABASE_URL: postgres://USER:PASSWORD@HOST:5432/postgres
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
      HASURA_GRAPHQL_ADMIN_SECRET: "change-me"
      HASURA_GRAPHQL_DEV_MODE: "true"

Chạy:

docker compose up -d

Mở:

http://localhost:8080/console

Nhập admin secret. Hasura console hiện ra. Kết nối PostgreSQL xong, vào tab Data, chọn schema, track table.

Nếu dùng Supabase hosted database, lấy connection string trong Supabase dashboard. Nên dùng connection string phù hợp môi trường server, không dùng key frontend.

Track table, relationship, function

Hasura không tự expose mọi thứ cho đến khi bạn track. Đây là điểm tốt: kiểm soát rõ object nào lên API.

Track bảng

Ví dụ có bảng:

create table public.projects (
  id uuid primary key default gen_random_uuid(),
  name text not null,
  owner_id uuid not null,
  created_at timestamptz default now()
);

create table public.tasks ( id uuid primary key default gen_random_uuid(), project_id uuid references public.projects(id), title text not null, status text not null default 'open', created_at timestamptz default now() );

Track projects, tasks. Hasura sinh query:

query {
  projects {
    id
    name
    tasks {
      id
      title
      status
    }
  }
}

Tạo relationship

Nếu foreign key có sẵn, Hasura gợi ý relationship:

projects.tasks: array relationship
tasks.project: object relationship

GraphQL mạnh nhờ relationship này. Schema database càng sạch, API càng ngon.

Track SQL function

Business query phức tạp có thể để trong SQL function:

create function public.search_tasks(keyword text)
returns setof public.tasks
language sql
stable
as $$
  select *
  from public.tasks
  where title ilike '%' || keyword || '%'
$$;

Track function, gọi qua GraphQL. Hữu ích khi query cần logic database, ranking, full-text search.

Permission: phần quan trọng nhất

Hasura mạnh, nhưng nguy nếu mở sai quyền. Đừng expose role admin ra client. Đừng dùng admin secret trong frontend.

Role phổ biến

anonymous: chưa đăng nhập
user: user thường
manager: quyền nâng cao
admin: backend nội bộ

Select permission

User chỉ đọc task thuộc project mình tham gia:

{
  "project": {
    "members": {
      "user_id": {
        "_eq": "X-Hasura-User-Id"
      }
    }
  }
}

Chỉ cho đọc vài cột:

id
title
status
created_at

Không cho đọc cột nhạy như internal_note, cost, deleted_at nếu không cần.

Insert permission

User tạo task vào project mình có quyền:

{
  "project": {
    "members": {
      "user_id": {
        "_eq": "X-Hasura-User-Id"
      }
    }
  }
}

Có thể preset cột:

{
  "created_by": "X-Hasura-User-Id"
}

Client không tự set created_by. Hasura tự ép theo session.

Update permission

Nên tách điều kiện:

– row nào được update
– cột nào được update

Ví dụ user chỉ đổi title, status, không đổi project_id, created_by.

Permission tốt giúp API tự động vẫn an toàn.

Business logic: Actions, Event Triggers, Scheduled Triggers

Không nên nhét mọi logic vào GraphQL CRUD. Có việc cần code riêng.

Actions

Dùng khi cần custom mutation/query. Ví dụ checkout, inviteMember, generateReport.

Hasura nhận GraphQL mutation, gọi webhook:

mutation {
  inviteMember(input: {
    email: "[email protected]",
    project_id: "..."
  }) {
    success
    message
  }
}

Webhook xử lý validation, gửi email, gọi payment, trả kết quả.

Event Triggers

Dùng khi database đổi thì chạy side effect:

– insert order -> gửi email
– update task done -> tạo notification
– new user -> tạo profile

Hasura nghe insert/update/delete rồi gọi webhook. Có retry, log, delivery status.

Scheduled Triggers

Dùng cho cron job:

– gửi báo cáo hằng ngày
– dọn dữ liệu tạm
– đồng bộ hệ thống ngoài

Migration từ Supabase API sang Hasura

Không cần big bang. Làm từng phần.

Bước 1: Giữ PostgreSQL hiện tại

Không đổi database. Không đổi bảng ngay. Kết nối Hasura vào cùng PostgreSQL.

Bước 2: Track read-only trước

Expose query cho vài màn hình cần GraphQL. Chưa bật mutation vội. So sánh kết quả với API cũ.

Bước 3: Thiết kế permission

Map role từ app hiện tại sang Hasura:

– user id lấy từ JWT
– role lấy từ claims
– tenant id nếu app multi-tenant
– org id nếu có workspace

Bước 4: Chuyển mutation

Chuyển từng luồng:

– tạo project
– cập nhật task
– mời member
– xoá mềm

Luồng đơn giản dùng mutation auto. Luồng phức tạp dùng Action.

Bước 5: Tối ưu query

Dùng:

– index PostgreSQL
– query plan
– limit/pagination
– aggregate cẩn thận
– allow list hoặc persisted queries nếu public API lớn

GraphQL không tự làm database nhanh. Query tốt vẫn cần index tốt.

Hasura so với Supabase API: chọn sao cho đúng?

Hasura hợp khi

– App cần GraphQL mạnh.
– Frontend cần query linh hoạt.
– Dữ liệu quan hệ nhiều.
– Permission theo row/column phức tạp.
– Cần realtime subscription.
– Team thích database-first.
– Muốn API sinh nhanh nhưng vẫn kiểm soát sâu.

Supabase API hợp khi

– CRUD REST đủ dùng.
– Team muốn all-in-one.
– Không muốn vận hành thêm service.
– App nhỏ hoặc MVP.
– Logic không quá lồng ghép.
– Realtime Supabase đã đáp ứng.

Dùng chung cũng ổn

Không cần chọn tuyệt đối. Có thể:

– Supabase Auth + Storage
– Supabase PostgreSQL
– Hasura GraphQL API
– Supabase Edge Functions hoặc server riêng cho webhook

Kiến trúc tốt là kiến trúc giảm việc, không tăng nghi thức.

Lưu ý vận hành production

Hasura vào production cần siết kỹ:

– Tắt console public.
– Đặt HASURA_GRAPHQL_ADMIN_SECRET mạnh.
– Không đưa admin secret vào client.
– Bật JWT auth.
– Cấu hình CORS đúng domain.
– Dùng HTTPS.
– Theo dõi slow query PostgreSQL.
– Giới hạn depth/complexity nếu cần.
– Dùng metadata/migrations trong Git.
– Backup database định kỳ.

Hasura metadata nên quản lý bằng CLI:

hasura metadata export
hasura metadata apply
hasura migrate apply

Đừng click console production rồi quên commit metadata. Dễ lệch môi trường.

Kết luận: Hasura là lớp GraphQL mạnh cho PostgreSQL

Hasura thay Supabase API tốt khi bạn cần GraphQL, permission chi tiết, realtime, và tốc độ tạo backend cao từ PostgreSQL. Điểm mạnh lớn nhất: không bắt viết CRUD lặp lại, nhưng vẫn cho kiểm soát permission, relationship, event, action.

Cách thực tế: đừng bỏ Supabase ngay. Giữ PostgreSQL, có thể giữ Auth/Storage, thêm Hasura làm GraphQL gateway. Track bảng từng phần. Bắt đầu read-only. Làm permission chắc. Sau đó chuyển mutation và business flow phức tạp.

Nếu database là trung tâm sản phẩm, Hasura giúp biến PostgreSQL thành backend GraphQL nhanh, rõ, mạnh. Nhưng sức mạnh này cần kỷ luật: schema sạch, permission đúng, migration có kiểm soát, index đầy đủ. Làm được vậy, Hasura không chỉ thay API Supabase. Nó thành xương sống dữ liệu cho app.

#dung #graphql #hasura #supabase #thay
Chia sẻ:
← Trước
Thay Supabase Auth bằng Clerk: Đăng nhập bảo mật trong 30 phút

Bài viết tương tự

Bình luận

Chưa có bình luận. Hãy là người đầu tiên!