PostgREST 从建表到 REST API 上线:4 层实操指南
【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest
PostgREST 把 PostgreSQL 的表、视图和函数直接变成 RESTful API,你不用写一行路由代码。这篇实操指南带你走完 4 步:跑通最小实例、看懂它的角色与权限体系、配好关键参数、完成生产加固。适合第一次接触这个项目、准备把它用在真实业务里的开发者。
1. 3 分钟拉通最小实例
目标:一个能返回数据的 REST 端点。
1.1 用 Docker 把数据库和 PostgREST 都拉起来
两个容器就够:一个 PostgreSQL,一个 PostgREST。
# docker-compose.yml version: '3' services: server: image: postgrest/postgrest ports: - "3000:3000" environment: PGRST_DB_URI: postgres://authenticator:mysecret@db:5432/postgres db: image: postgres ports: - "5432:5432" environment: POSTGRES_DB: postgres POSTGRES_USER: authenticator POSTGRES_PASSWORD: mysecretPGRST_DB_URI是 PostgREST 唯一必须知道的配置:它用这个连接串去连数据库。官方镜像基于 scratch 构建,总大小约 14MB,里面只有一个静态二进制。
1.2 建一张表,配一个最小配置文件
进容器建一张todos表,并创建两个角色:web_anon(匿名请求用)和登录角色authenticator。
CREATE SCHEMA api; CREATE TABLE api.todos ( id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, done boolean NOT NULL DEFAULT false, task text NOT NULL ); INSERT INTO api.todos (task) VALUES ('finish tutorial 0'); CREATE ROLE web_anon NOLOGIN; GRANT USAGE ON SCHEMA api TO web_anon; GRANT SELECT ON api.todos TO web_anon; CREATE ROLE authenticator NOINHERIT LOGIN PASSWORD 'mysecret'; GRANT web_anon TO authenticator;注意最后一行:GRANT web_anon TO authenticator是后面角色切换的基础,漏了它请求会直接 401。
配置文件只需 3 行:
# postgrest.conf db-uri = "postgres://authenticator:mysecret@localhost:5432/postgres" db-schemas = "api" db-anon-role = "web_anon"db-schemas决定哪些 schema 会暴露成接口,db-anon-role指定没带身份的请求用哪个角色执行。
1.3 验证端点,404 时先查 schema cache
postgrest postgrest.conf # 输出:Starting PostgREST ... # Successfully connected to PostgreSQL ... # API server listening on port 3000另开一个终端请求它:
curl http://localhost:3000/todos # 输出:[{"id":1,"done":false,"task":"finish tutorial 0"}]看到 JSON 数组说明通了。⚠️ 注意:如果你重启 PostgREST 之后新建了表,请求会 404。因为 PostgREST 启动时会把表结构缓存进 schema cache(模式缓存),不会实时发现新对象。在 psql 里执行NOTIFY pgrst;触发重载,再请求就正常了。
1.4 试写操作,观察权限如何生效
curl -X POST http://localhost:3000/todos \ -H "Content-Type: application/json" \ -d '{"task": "do bad thing"}'返回 401 和"permission denied for table todos"。这不是配置错误——web_anon只有SELECT权限。PostgREST 的安全模型在下一节展开。
2. 看懂它的角色与权限体系
2.1 三种角色各管什么
PostgREST 用 PostgreSQL 的 role(角色,即数据库里的"用户"或"用户组")来做全部授权。三类角色分工明确:
authenticator:登录数据库的角色,权限最小,唯一职责是"变身"成其他角色web_anon:未认证请求的默认身份webuser等:已认证用户对应的角色
CREATE ROLE authenticator LOGIN NOINHERIT NOCREATEDB NOCREATEROLE NOSUPERUSER; CREATE ROLE anonymous NOLOGIN; CREATE ROLE webuser NOLOGIN;NOLOGIN意味着用户角色不能直接登录,只能被authenticator切换,这是防止旁路的关键。
2.2 每个请求如何匹配到一个数据库角色
客户端带上 JWT(JSON Web Token,一种带签名的身份令牌),JWT 里的role声明指向某个数据库角色。PostgREST 验签通过后,用SET LOCAL ROLE切到该角色再执行查询:
curl "http://localhost:3000/todos" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." # PostgREST 内部执行:SET LOCAL ROLE webuser;GRANT webuser TO authenticator; GRANT SELECT, INSERT ON api.todos TO webuser;没带 JWT、或 JWT 里没有role声明,就落到前文提到的db-anon-role。如果某个角色没被GRANT给authenticator,对应请求会直接失败——这是最常见的"权限不通"原因。
2.3 为什么授权全部交给数据库
PostgREST 自己只管"你是谁"(认证),"你能干什么"(授权)完全由数据库的角色和权限决定。这样做的好处是只有一份安全事实来源:你在 psql 里能看到的权限,就是 API 上生效的权限。SECURITY DEFINER函数(以函数属主身份执行的函数)、RLS 策略都直接参与 API 行为,无需在应用层重复实现。
官方教程用电影、影星、影片这几张表演示外键关系,PostgREST 会基于这些外键自动生成嵌入查询能力。
3. 关键配置项:三种来源与热重载
3.1 配置文件与环境变量怎么选
环境变量规则:参数名大写、前缀PGRST_、连字符换成下划线。
# 文件里这样写 db-uri = "postgres://user:pass@host:5432/dbname" server-port = 3000# 容器里这样写 export PGRST_DB_URI="postgres://user:pass@host:5432/dbname" export PGRST_SERVER_PORT=8080优先级:环境变量 > 配置文件。Docker 部署用环境变量,裸机部署用配置文件,两者别混着改同一个参数。
3.2 把敏感配置搬进数据库
db-pre-config指向一个数据库函数,可以在库里动态下发配置,密钥不落盘:
CREATE SCHEMA postgrest; GRANT USAGE ON SCHEMA postgrest TO authenticator; CREATE FUNCTION postgrest.pre_config() RETURNS void AS $$ SELECT set_config('pgrst.db_schemas', 'api', true), set_config('pgrst.jwt_secret', 'reallyreallyreallyreallyverysafe', true); $$ LANGUAGE sql;注意库里参数名用下划线:db_schemas而不是db-schemas。配置文件里只需一行db-pre-config = "postgrest.pre_config"。
3.3 修改后如何生效
大多数参数支持热重载,不用重启进程:
# 方式一:发信号 killall -SIGUSR2 postgrest # 方式二:在 psql 里通知 NOTIFY pgrst, 'reload config';但环境变量不支持重载——容器改了PGRST_*后必须重启,或改用上面的库内配置。
关键参数速查:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
db-uri | String | 必填 | PostgreSQL 连接串 |
db-schemas | String | public | 暴露成 API 的 schema,逗号分隔 |
db-anon-role | String | 无 | 匿名请求使用的角色,不设则禁止匿名访问 |
jwt-secret | String | 无 | JWT 验签密钥,至少 32 字符 |
db-pool | Int | 10 | 连接池大小 |
db-max-rows | Int | 无限制 | 单次查询最大返回行数 |
openapi-mode | String | follow-privileges | OpenAPI 文档生成模式 |
admin-server-port | Int | 无 | 管理端口,提供健康检查与指标 |
4. 生产级加固:RLS、连接池与健康检查
4.1 行级安全:让每个用户只看自己的行
RLS(行级安全,即按行过滤谁能看到哪条数据)是 PostgREST 最省代码的隔离手段。
ALTER TABLE api.todos ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON api.todos USING (owner = current_setting('request.jwt.claims', true)::json->>'sub');策略里的request.jwt.claims由 PostgREST 注入当前请求的 JWT 声明。不同用户的请求查同一张表,各自只看到自己的行——你不需要在 SQL 视图里手写任何过滤逻辑。
4.2 连接池与慢查询防线
PostgREST 内部维护连接池,生产上建议显式收紧:
db-pool = 20 db-pool-max-lifetime = 3600 db-pool-max-idletime = 30同时给每个被切换的角色设置语句超时,防止慢查询占死连接:
ALTER ROLE webuser SET statement_timeout = '15s';4.3 开启管理端口
admin-server-port是独立于 API 的管理端口,提供健康检查和指标:
curl -I http://localhost:3001/livelive只确认进程活着,返回 200 或 500。
curl -I http://localhost:3001/readyready额外检查连接池和 schema cache 状态,异常时返回 503,适合挂到负载均衡器的探活上。
5. 常见踩坑与排查
5.1 401 permission denied:查 GRANT 链
按顺序检查三件事:该角色有没有被GRANT ... TO authenticator、角色对 schema 有没有USAGE、对表有没有对应操作权限。写操作还要单独给序列授权:
-- 诊断:看角色实际拥有哪些表权限 SELECT table_name, privilege_type FROM information_schema.role_table_grants WHERE grantee = 'webuser';-- 修复:补上插入自增列所需权限 GRANT USAGE ON SEQUENCE api.todos_id_seq TO webuser;POST 报 401 而 SELECT 正常,十有八九是漏了序列权限。
5.2 404 resource not found:查 schema cache
三种常见原因:表不在db-schemas里、表名拼错、对象是启动之后新建的。最后一种执行NOTIFY pgrst;重载即可。
5.3 用管理端点看它"看到了什么"
curl http://localhost:3001/schema_cache返回 JSON 里按dbTables、dbRoutines等字段列出 PostgREST 当前缓存的对象。你要找的表不在列表里,说明它根本没被识别进来——问题在 schema 配置或权限,而不是缓存时序。
下一步
- 把匿名角色换成最小只读集,再给写操作角色逐表补
GRANT,参考 docs/references/auth.rst 里的角色模型。 - 给核心表启用 RLS,用不同
sub声明的 JWT 各发一次请求,验证行隔离是否按预期生效。 - 启用
openapi端点(默认开启),把它接入网关或前端文档站,让 API 文档跟着数据库结构自动更新。
【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考