Supabase GraphQL Direct протыва вашага сабскіптаванага Apollo Backend
Паруцьце pg_graphql, які выкаліваюцца няпраздзе з Supabase, з адзінам Apollo серверам — аутантыкацыя, RLS, падпіскі, а таксама калі выграе гібрыдны шлях Edge Function.
GraphQL — это язык запитаў, а не среда выконання. Яго можна выклікваць з колькох месцаў:
- Вбудованы
pg_graphqlу Supabase — схема, створаная на базе PostgreSQL, хоставаная Supabase, практычна без налаштоўкаў - Спецыяльны бэкенд — Node, Python чытаў Go, які запускае Apollo Server, Hasura, Pothos чытаў падобныя рашэнняя, якія належаць вам і якія вы самі розмешчаеце
У будзь-якам случае фронтэнд можа выкарыстоўваць Apollo Client. Зменяецца толькі месца, дзе знаходзится схема GraphQL, і тое, хто яю контролюе.
Система Vision Expert System выбірае падход через Supabase:
// src/client/supabase-grphql-apollo.client.js
const httpLink = new HttpLink({
uri: `${SUPABASE_URL}/graphql/v1`, // ← Supabase's built-in endpoint
});
Няма процэса Express, няма Apollo Server, няма ручна напісаных рашэнняў, няма дадатковага розмешчання. API-інтерфейс — це схема базы дадзеных.
Эскізы архітектуры
Падход А: Чыраз Supabase
Браузер співае безпосередна з Supabase GraphQL. Аутэнтыкацыя адбываецца за дапамогою JWT у Supabase. Безпека на рэвеніі строк — гэта механізм контролю.
Падчынны B: Адзінольны бэкенд
Браузер выступае ў зв’язку з вашым серверам GraphQL. Разьяснювачы выконваюць запиты да Supabase (або іншых джэрел) за дапамогою адмінскага SDK чыта SQL. Вы самі ствараеце типы і поля.
Інтуіцыя па прымэру
Прямой режым оптымаўна падходзіць для викорыстання функцый CRUD без неабяжнасці хоставаць API. Адзінольны режым оптымаўна падходзіць для спецыяльных полей, з’ѐеднанняў калькольнасця служб і падпісаў у стыле GraphQL. Тэксты кліента Apollo аднаковыя; розныя толькі права на кераванне схемай і правіламі.
Praktыка викорыстання Supabase-direct
Як гэта працюе
Пад час запуску pg_graphql аналізуе базу дадзеных PostgreSQL і стварае цэлысткі GraphQL API. Табелі ператвараюцца на типы Калекцый з функцыйямі CRUD, прыстосаванымі для з’ѐеднанняў у стыле Relay.
Канфігурацыя кліента Apollo (гэты проект)
// Two required headers — no custom backend token scheme
const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
apikey: SUPABASE_ANON_KEY, // identifies the Supabase project
Authorization: `Bearer ${accessToken}`, // Supabase JWT for RLS
"Content-Type": "application/json",
},
}));
const httpLink = new HttpLink({
uri: `${SUPABASE_URL}/graphql/v1`, // Supabase endpoint — no server to host
});
Формат запитаў
Калекцыі павінны адпавядаць шаблону з’ѐеднання:
query LoadStaff {
staffCollection { # ← always "Collection"
edges { # ← always "edges"
node { # ← always "node"
id
first_name
role { # ← relations via FK are auto-resolved
role_name
}
}
}
}
}
Формат мутацый
mutation AddStaff($firstName: String!, $email: String!) {
insertIntostaffCollection( # ← prefix is always "insertInto"
objects: { first_name: $firstName, email: $email }
) {
records {
id
}
}
}
Безпека ў базе дадзеных
Палітры RLS адначыя, хто можа бачыць калікве. «Бэкенд» — это PostgreSQL:
-- Only active staff can be read
CREATE POLICY "select active staff"
ON vision_expert.staff
FOR SELECT
USING (is_active = true AND auth_user_id = auth.uid());
Нават спецыяльна створаная запита GraphQL не можа абійсці RLS; фільтрацыя выконвуецца ўнутры Postgres.
Меры, якія існуюць пад час працы без посередніка
- Для спецыяльных поль, якіх нэмаў у базе дадзеных, патрэбны функцыяй калікве адзор вію.
- Для вырахоўваных/віртуальных поль патрэбны вырахоўваныя столбцы калікве адзор вію.
- Удоўжненне адзінага рэзалвера за дапамою запыту REST ад трэцьяго сторонніка є складным без Edge Functions.
- Багатыяпрыемнікавыя рабочыя процесы з адворачэнням змян выконвуецца ў функцыях базы дадзеных калікве на фронтэндзе.
- Назвы паўтараюцца за правіламі
pg_graphql— знакі падкрэсла застаюцца, таму імёні на кшталтhead_officeCollectionзастаюцца такімі.
Практычны выкарыстоўванне аддзельнага бэкенду
Як гэта працюе
Вы запускаеце Apollo Server (альбо аднакласныя сэрвісы), ствараеце схему і пісваеце рэзалверы, якія вызываюць Supabase admin, Prisma або SQL.
Канфігурацыя кліента Apollo
// Separate backend — your own auth token, your own endpoint
const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
Authorization: `Bearer ${yourCustomJwt}`,
"Content-Type": "application/json",
},
}));
const httpLink = new HttpLink({
uri: "https://api.yourapp.com/graphql", // your server
});
Адзінаковая схема
# You define every type by hand
type Staff {
id: ID!
firstName: String!
lastName: String!
fullName: String! # computed field — not in DB
role: Role!
branch: Branch!
subordinates: [Staff!]! # custom logic
}
type Query {
staff(id: ID!): Staff
staffByBranch(branchId: ID!): [Staff!]!
}type Mutation {
addStaff(input: AddStaffInput!): StaffPayload!
deactivateStaff(id: ID!): Boolean!
}
Рэзалверы
// server/resolvers/staffResolvers.js
const Query = {
staffByBranch: async (_, { branchId }, { supabaseAdmin, currentUser }) => {
// Business logic: only managers can list their own branch
if (currentUser.role !== "manager" && currentUser.branchId !== branchId) {
throw new ForbiddenError("Access denied");
}
// Fetch from Supabase using admin SDK (bypasses RLS)
const { data, error } = await supabaseAdmin
.from("staff")
.select("*, branch(*), role(*)")
.eq("branch_id", branchId); return data;
},
};const Staff = {
// Computed field not in DB
fullName: (parent) => `${parent.first_name} ${parent.last_name}`,
};
Шляхі SDK для адміністрацыі абходзяць RLS, таму автарызацыя павінна быць реалізаваная ў коде рэзалвера з строгім сяброўствам.
Дэтальны аналіз: што на самай працы разлічваецца
1. Прабег аутантыкацыі
Supabase-direct:
User logs in → supabase.auth.signInWithPassword()
→ Supabase returns JWT
→ JWT stored in session
→ Apollo authLink reads JWT from supabase.auth.getSession()
→ JWT sent in Authorization header with every GraphQL request
→ Supabase validates JWT and enforces RLS
// Token is read dynamically from the Supabase session
let accessToken = null;
supabase.auth.getSession().then(({ data: { session } }) => {
accessToken = session?.access_token ?? null;
});
supabase.auth.onAuthStateChange((_event, session) => {
accessToken = session?.access_token ?? null;
});
Адзінаковы бэкенд:
User logs in → POST /auth/login (your endpoint) or Supabase Auth
→ Your server returns a custom JWT
→ Frontend stores JWT
→ Apollo authLink reads JWT from localStorage / context
→ JWT sent to your server
→ Your server validates JWT in middleware
→ Resolver runs with the validated user context
У прямам режыме не патрэбна адменстрацыя токенаў — JWT ад Supabase выступае як доказ заходжання і кранты для базы дадзеных. Адзінаковы бэкенд додае ўзлёт, але дазволяе формаваць тэрміны дзейснасці і параметры заяваў.
2. Паўязка Apollo link
Supabase-direct:
// Two specific headers, one endpoint
const link = offlineMutationLink
.concat(authLink) // adds apikey + Bearer
.concat(httpLink); // → supabase.co/graphql/v1
Адзінаковы бэкенд:
// One standard auth header, your endpoint
const link = authLink // adds your token
.concat(httpLink); // → api.yourapp.com/graphql
Тая ж сама ідея setContext + HttpLink. Разліки заключаюцца ў URL і тым, якія заголовкі є обав’язковымі.
3. Запиты і зміны
Supabase-direct — імены, які генеруюцца, є фіксаванымі:
# Table: staff → Query: staffCollection, Mutation: insertIntostaffCollection
query {
staffCollection(filter: { is_active: { eq: true } }) {
edges { node { id first_name } }
}
}
Адзельны бэкенд — вы самі называеце все:
# You chose the name "activeStaff"
query {
activeStaff {
id
fullName # computed in resolver
avatarUrl # fetched from a CDN API in resolver
}
}
Адзін створаны схема можа спроставіць вялікі структуры, з’еднаць службы і вырахаваць похідныя поля ў аднай вядомасі. У режыме Direct вяртаецца тое, што ўтримваюць таблицы.
4. Дзе знаходзяцца правіла бізнесу
Supabase-direct:
Business logic → PostgreSQL functions, triggers, and RLS policies
OR handled in the React frontend (as in this project)
Прыклад — пераконтроль наявнасці дублікатав NIC/электронной пашты у фронтендзе перад дадзенням:
// Frontend handles the business rule: check for dup NIC/email before inserting
const { data: dupData } = await checkDuplicate({ variables: { nic, email } });
const nicExists = dupData?.nicCheck?.edges?.length > 0;
if (nicExists) {
alert("A staff member with this NIC already exists.");
return;
}
await addStaff({ variables: { ... } });
Адзельны бэкенд:
// Backend resolver handles the business rule
const addStaff = async (_, { input }, { db }) => {
const existing = await db.staff.findFirst({
where: { OR: [{ nic: input.nic }, { email: input.email }] }
});
if (existing) throw new UserInputError("NIC or email already exists");
// Atomic transaction: create auth user + insert staff profile
return await db.$transaction([
supabaseAdmin.auth.admin.createUser({ email: input.email }),
db.staff.create({ data: input }),
]);
};
Правіла бэкенду залишаюцца централізаванымі для кожнаго користувальця (веб, мобайль, партнеры). Правіла толькі для фронтенду розсіююцца і легка працягваюцца.
5. Модэль безпекі
У прымаму режыме сложней паспаліць настройкі, які моглы б спрычыніць нехтаўны вывар падаў, таму што Postgres контролюе доступ. Аддзельны бэкенд ёсць болей гнучкі, але больш залежыць ад рэтельнага выбору средстваў для разв’язвання прычын.
6. Падпісвання і рэальны час
Supabase-direct выкарыстоўвае каналы Supabase Realtime, а не падпісвання GraphQL:
// Supabase Realtime — separate from GraphQL
const channel = supabase
.channel("staff-changes")
.on("postgres_changes", { event: "*", schema: "vision_expert", table: "staff" },
(payload) => { refetch(); }
)
.subscribe();
Гэты падход аддзельны ад Apollo; кліент GraphQL сам по сабе не отрымае паведамленняў у рэальны час.
Аддзельны бэкенд можа запростаць справжнія падпісвання GraphQL через WebSocket:
subscription {
staffAdded {
id
first_name
role { role_name }
}
}
// Apollo Client with WebSocket link
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
const wsLink = new GraphQLWsLink(
createClient({ url: "wss://api.yourapp.com/graphql" })
);
7. Падтрымка паўнай самастойнасці
Обе стороны могу архіваваць змены, якія выкалічваюцца паўнай самастойнасцю, через Apollo Link. Vision Expert System робіць гэта ў прымаму режыме, выкарыстоўваючы RxDB як локальную канцэльеру.
Падход у сутнасі той самы:
Offline mutation → ApolloLink intercepts → stores in local DB → syncs on reconnect
Адкантэнацыя токена пасля перыякнуцья зазвычай ўсё простае, калі вы самі кантролюеце жыцёвы цикл токена. У Supabase вам неабходна паўтарна перакананасць, што JWT застаецца чынным, прытымкі практычна не трэба.
Калі падходзіць Supabase-direct
Выбірайте яго, калі:
- Работа з дадзенням майже выключна CRUD і адбываецца за дапамою табелей
- Вы хочаце запускань без адпаведнага хоста API
- Команда мала, а глыбіна бэкенду обмежана
- Логіка падходзіць пад функцыі PostgreSQL і RLS
- Існуе фактычна адны корыстнік фронтэнда
- Вы хочаце мінімальныя витраты на хостынг для шара API
- Запиты залишаюцца сфокусаванымі на табелях без з’еднанняў межа служб
Гэта падходзіць для Vision Expert System: внутраняго інструмента з калькама ролей, усі даны ў Supabase, RLS па ролях і відгалужэннях, адны фронтэнд.
Калі патрэбны околачы бэкенд
Дадзіце яго, калі:
- Вам патрэбны вычыслены/вяртуальныя поля, якіх няма ў БД
- Адпаведны адказ GraphQL павінен агрэгаваць даны з Supabase, а таксама з сервісамі платежаў, CRM чы іншымі
- Багатоэтапныя транзакцыі павінны заставацца атамарнымі ўсередзіне розных таблиц і сервісаў
- Зовнішнія разработчыкі будуць выкарыстоўваць публічны API
- Вам патрэбны падпісы GraphQL як спосаб прыманення данных у рэальны час
- Бізнес-правілы занадта складныя для реалізаціі за дапамогою SQL
- GraphQL становіцься шлюзам для федэрацыі ў структуре мікросервісаў
- Вам патрэбны ліміты частоты запытоў на рэвэле, пераверкі чы журналы аудыту на рэвэле
- Сгенераваныя імены
pg_graphqlє непрыемнымі і не можна іх выправіць
Гібрыдны падход
Багатыя продакшн-проекты выкарыстоўваюць аба падходы разам:
- Прямы GraphQL для звычных запытоў на чытанне і запіс
- Supabase Edge Functions для тых 10% сцэнарыяў, дзе ён не падходзіць: адмінскі SDK (безпечны спосаб айханаў RLS), запыты да сторонніх сервісаў, багатоэтапныя процесы
Frontend Apollo Client
│
├── /graphql/v1 → Supabase pg_graphql (standard CRUD)
│
└── /functions/complex-operation → Supabase Edge Function (business logic)
→ calls Supabase admin SDK internally
Вы застаўляеце шырокі спектар трафіку на режым працы без адстаўкі, які забезпечвае высокую швальнасць і мінімальную падтрымку, а гнучкасць, прыемную для бэкенду, застаўляеце там, дзе яна практычна неабходная — без неабяжнай наладкі цэлага сервера, які працавае ўвесь час для всего.