Перейти к основному содержимому

Таблицы и REST

GET|HEAD|POST|PATCH|DELETE https://data.layero.ru/<база>/rest/v1/<таблица>

Форма запроса — PostgREST, поэтому фильтры, сортировка, встроенные ресурсы и заголовки Prefer работают так же, как в документации Supabase.

# первые пять записей, новые сверху
curl "https://data.layero.ru/moya-baza/rest/v1/entries?select=id,name,created_at&order=created_at.desc&limit=5" \
-H "apikey: pk_live_…"

# одна запись по условию
curl "https://data.layero.ru/moya-baza/rest/v1/entries?id=eq.42&select=*" \
-H "apikey: pk_live_…"

Если limit не задан, шлюз ставит свой — 1000 строк. Запрос без предела выедал бы пул соединений, общий для всех баз платформы.

Доступ: грант плюс политика

Свежая база не отдаёт по API ни одной таблицы. Чтобы таблица стала видна, роли нужен грант, а таблице — политика RLS:

GRANT SELECT ON public.entries TO layero.role('anon');
ALTER TABLE public.entries ENABLE ROW LEVEL SECURITY;

CREATE POLICY entries_read_own ON public.entries
FOR SELECT TO PUBLIC
USING (owner_id = auth.uid());

🚨 Имя роли берите из layero.role(), а не из pg_roles. Имя содержит идентификатор базы, вписать его буквально нельзя, и соблазн найти по шаблону (rolname ~ '^u_.*_anon$') выглядит естественным. Он неверен: список ролей общий на весь сервер, шаблон совпадает с ролями чужих арендаторов, и права уезжают не туда. Функция layero.role('anon'|'auth'|'svc') есть в каждой базе с включённым API и возвращает вашу роль.

Проверьте выданное не на глаз: панель выполнит запрос от роли ключа — от anon, от вошедшего пользователя или от секретного ключа — и откатит транзакцию.

Отказы, которые вы увидите

ОтветЧто это значит
unknown_tableтаблицы нет в каталоге роли, под которой открыт запрос — имя этой роли названо в тексте отказа. Почти всегда это грант, ушедший не той роли
no_table_grantтаблица есть, но у роли нет нужного права; в hint лежит готовый GRANT
permission_denied / 42501отказ самой базы
пустой массивгрант есть, а политика RLS не пускает ни одной строки

Разница между последними двумя — самая частая точка непонимания: пустой ответ — не ошибка, а работающая политика.

Запись

// insert + вернуть вставленное (так по умолчанию делает supabase-js)
await db.from("entries").insert({ name: "Аня" }).select();

Prefer: return=representation возвращает строку — и попадает под политику чтения, а не только вставки. Если политика чтения не пускает автора, вставка пройдёт, а запрос ответит отказом RLS; подробности и рецепт — Грабли переезда.