news 2026/9/11 1:53:50

PostgREST 完全指南:把 PostgreSQL 数据库直接变成 RESTful API

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PostgREST 完全指南:把 PostgreSQL 数据库直接变成 RESTful API

PostgREST 完全指南:把 PostgreSQL 数据库直接变成 RESTful API

【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest

PostgREST 是一个独立的 Web 服务器,能够把任意一个已有的 PostgreSQL 数据库直接转化为一套完全符合 REST 规范的 API。它的核心思路是:数据库本身的结构约束与权限体系决定了 API 的端点与操作,应用层不再需要手写 CRUD 代码。读完本文,你将掌握 PostgREST 的安装与启动方式、完整 CLI 命令用法、性能设计原理、JWT 认证与数据库授权的安全模型,以及如何用数据库 Schema 实现 API 版本化与 OpenAPI 自文档化。

项目定位:数据库即单一事实来源

PostgREST 项目在仓库根目录 README.md 中的自我定位非常明确:"PostgREST serves a fully RESTful API from any existing PostgreSQL database"——它从任何已有的 PostgreSQL 数据库提供一套完整的 RESTful API,并且比手工从零编写的 API 更干净、更符合标准、更快。

这一设计哲学在文档入口 docs/index.rst 中被进一步阐释为"数据库作为单一事实来源"(Database as Single Source of Truth):

  • 声明式编程:让 PostgreSQL 自己完成表连接并交给查询规划器优化,而不是在代码里循环遍历行;给数据库对象赋权限,而不是在控制器里写权限守卫;用约束替代散落在代码里的健全性检查。
  • 无泄漏抽象:整个链路不涉及 ORM,创建视图就是在 SQL 中完成,性能影响完全可知。数据库管理员无需编写任何自定义程序即可从零搭建 API。
  • 只做一件事:PostgREST 聚焦数据中心的 CRUD 操作,与 Nginx 等工具配合良好,将数据逻辑与其他关注点清晰分离。

PostgREST 将三种数据库对象暴露为 API 资源:表(tables)、视图(views)和函数(functions),详见 docs/references/api.rst。

快速上手:安装与第一个请求

安装方式

官方文档 docs/explanations/install.rst 提供了多种安装途径:

  1. 预编译二进制:从 release 页面下载 macOS、Windows、Linux 和 FreeBSD 的预编译产物,其中 Linux 二进制是静态可执行文件,可在任何 Linux 发行版上直接运行:

    # UNIX 平台解压 tar Jxf postgrest-[version]-[platform].tar.xz # Windows 直接解压 zip
  2. 系统包管理器(详见 docs/shared/installation.rst):

    # macOS (Homebrew) brew install postgrest # FreeBSD pkg install hs-postgrest # Arch Linux pacman -S postgrest # Nix nix-env -i postgrest # Windows (Chocolatey / Scoop) choco install postgrest scoop install postgrest
  3. Docker:官方镜像postgrest/postgrest,通过环境变量PGRST_DB_URI传入连接串:

    docker run --rm --net=host \ -e PGRST_DB_URI="postgres://app_user:password@localhost/postgres" \ postgrest/postgrest

    注意:Docker on Mac 不支持--net=host,需要创建 IP 别名(如sudo ifconfig lo0 10.0.0.10 alias)并在pg_hba.conf中放行该地址。

  4. 从源码构建:使用 Stack 构建(依赖libpq-devlibgmp-devzlib1g-dev等):

    git clone https://github.com/PostgREST/postgrest.git cd postgrest stack build --install-ghc --copy-bins --local-bin-path /usr/local/bin

    PostgreSQL 版本要求为>= 14(即 PostgreSQL 官方仍支持的版本)。

启动服务器

PostgREST 服务器把配置文件作为唯一参数:

postgrest /path/to/postgrest.conf # 也可以用 -e 生成示例配置文件,编辑后使用 postgrest -e > postgrest.conf

先执行postgrest --help查看用法说明,这是 README 中给出的第一步验证方式:

postgrest --help

README 中的 Usage 小节 明确指出:安装完成后调用postgrest --help即可获得完整的命令帮助。配置文件的最小可用形式至少需要db-uri(数据库连接串)、db-schemas(暴露的 schema)、db-anon-role(匿名角色)三项,完整参数参考见 docs/references/configuration.rst。测试目录中的 test/io/configs/defaults.config 展示了实际配置文件的写法。

CLI 命令行详解:从源码看实现

PostgREST 的命令行由 src/library/PostgREST/CLI.hs 基于optparse-applicative实现,入口在 src/executable/Main.hs——main先设置标准输入输出的行缓冲,然后调用CLI.readCLIShowHelp解析参数并分发执行。完整命令一览(见 docs/references/cli.rst):

Usage: postgrest [-v|--version] [-e|--example] [--dump-config | --dump-schema | --ready] [FILENAME] Available options: -h,--help Show this help text -v,--version Show the version information -e,--example Show an example configuration file --dump-config Dump loaded configuration and exit --dump-schema Dump loaded schema as JSON and exit (for debugging, output structure is unstable) --ready Checks the health of PostgREST by doing a request on the admin server /ready endpoint FILENAME Path to configuration file

各选项的源码级说明如下:

选项作用源码依据
FILENAME配置文件路径,为位置参数CLI.hs 中的configFileOption
-v, --version打印版本号versionFlag通过prettyVersion输出
-e, --example输出一份示例配置文件exampleParser直接输出Config.exampleConfigFile
--dump-config输出加载后的完整配置并退出对应RunCommandCmdDumpConfig
--dump-schema把 Schema Cache 以 JSON 形式 dump 出来(调试用,结构不稳定)CmdDumpSchema调用querySchemaCache
--ready对管理服务器的/ready端点发健康检查请求,成功退出码 0,失败为 1ClientCommandCmdReady

--ready的典型输出为:

$ postgrest --ready OK: http://localhost:3001/ready

注意:当server-host配置了特殊主机名时不能使用--ready,建议改为localhost

--dump-config值得单独说明:它输出的配置是配置文件 + 环境变量 + 数据库内配置(in-db config)三层合并后的最终结果,非常适合排查"为什么实际生效的配置和我写的不一样"这类问题。CLI 主流程中,main会先读取配置再按命令分发(见 CLI.hs 的main函数),运行类命令则会初始化AppState并在退出时显式关闭到 PostgreSQL 的连接(对应 CLI.hs 中runAppCommand的 bracket 结构)。

性能:为什么 PostgREST 这么快

README 的 Performance 小节 给出了简洁的结论:在 Heroku 免费档上可以达到 2000 请求/秒的亚秒级响应(这是 README 声明的基准数据)。速度来自三个层面的设计:

第一层:编译语言 + 轻量线程的 HTTP 服务器

服务端使用 Haskell 编写,运行在 Warp HTTP 服务器之上(详见 docs/explanations/architecture.rst 中关于 App 模块的说明)。相比解释型语言写的服务,编译语言配合轻量线程意味着更低的调度开销和更高的并发能力。

第二层:把计算尽量下推到数据库

PostgREST 刻意把尽可能多的计算委托给数据库完成,包括:

  • 直接在 SQL 中序列化 JSON 响应——不需要在应用层逐行转 JSON;
  • 数据校验——由数据库约束完成;
  • 授权——由数据库角色权限完成;
  • 行计数与数据检索合并执行——一条查询同时拿到结果和总数;
  • 数据写入使用单条命令——通过returning *一条语句完成插入/更新并返回结果。

从源码结构看,这一设计贯穿请求处理的每一层:ApiRequest.hs 负责解析 URL 查询串与请求头/请求体;Plan.hs 结合 Schema Cache 生成内部 AST,并补齐ON CONFLICT (pk)等带外 SQL 细节;Query.hs 生成参数化、预编译的 SQL 语句——只有到这一阶段才会从连接池取出数据库连接。

第三层:通过 Hasql 高效使用数据库

使用 Hasql 库带来的效率优势:

  • 维护数据库连接池——连接复用避免反复建连;
  • 使用 PostgreSQL 二进制协议——比文本协议更紧凑高效;
  • 无状态设计——服务器本身不保存会话状态,从而支持水平扩展。

此外,JWT 签名校验(尤其 RSA 这类非对称算法)较慢,PostgREST 内置了有界 JWT 缓存,使用 SIEVE 算法淘汰,默认开启,可通过jwt-cache-max-entries配置;文档 docs/references/auth.rst 指出其压测显示简单 GET 请求吞吐量提升约 20%,代价是略多的内存占用。jwt-secret变更并重载配置时缓存会重置。

安全模型:JWT 认证 + 数据库授权

README 的 Security 小节 概括了 PostgREST 的安全哲学:PostgREST 负责认证(authentication),授权(authorization)完全交给数据库。服务器通过 JSON Web Token 处理认证,授权则依赖数据库中定义的角色信息,从而保证安全策略只有数据库这一处声明式的事实来源。服务器在与数据库交互时,会承担当前已认证用户的身份,连接期间它做不了用户本人做不了的事情。

三种角色的分工

PostgREST 使用三类数据库角色(详见 docs/references/auth.rst 与 docs/explanations/db_authz.rst):

  • authenticator(认证者):用于连接数据库,权限应尽可能受限,它的职责是"变成"其他角色来服务 HTTP 请求;
  • anonymous(匿名角色):处理未认证请求;
  • user(用户角色):每个已认证 Web 用户对应的数据库角色。
CREATE ROLE authenticator LOGIN NOINHERIT NOCREATEDB NOCREATEROLE NOSUPERUSER; CREATE ROLE anonymous NOLOGIN; CREATE ROLE webuser NOLOGIN;

角色名本身可配置(对应db-uridb-anon-role配置项),并非固定名称。

用户冒充机制(User Impersonation)

认证成功后,PostgREST 切换到请求指定的用户角色;认证失败则切换到匿名角色。这一"冒充"机制在 PostgreSQL 中通过SET ROLE语句实现,被冒充角色的设置会一并生效:

SET LOCAL ROLE user123;

前提是数据库管理员已经授权 authenticator 切换到这些角色:

GRANT user123 TO authenticator; GRANT anonymous TO authenticator;

JWT 认证细节

PostgREST 使用 RFC 7519 定义的 JWT 做认证,因此无需数据库查询即可完成验证,保持无状态。JWT 中所有 claim 都被允许,但 PostgREST 只关心role声明(其路径可用jwt-role-claim-key配置):

{ "role": "user123" }

客户端通过Authorization: Bearer <jwt>头携带令牌(Bearer大小写均可):

curl "http://localhost:3000/foo" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

签名验证支持对称与非对称两种方式:

  • 对称密钥:jwt-secret配置为普通字符串时按 HMAC-SHA256 口令解释:

    jwt-secret = "reallyreallyreallyreallyverysafe"
  • 非对称密钥:jwt-secret可接受字面量 JWK 或 JWKS({ "keys": [jwk1, jwk2] }),也可用@filename引用 JWK 文件:

    jwt-secret = "@rsa.jwk.pub"

claim 校验包含三类内置逻辑:

  1. 时间类 claimexp(过期时间)、iat(签发时间)、nbf(生效时间)都会校验,且允许 30 秒的时钟偏差;
  2. kid校验:JWT 带kid时按匹配的 JWK 验证,无匹配则返回 401;不带kid时逐个尝试 JWK 直到找到可用密钥;
  3. aud校验jwt-aud未设置时接受所有 audience;设置后校验aud声明(支持字符串或字符串数组),匹配失败返回 401。

授权:完全由数据库完成

授权细节在 docs/explanations/db_authz.rst 中有完整论述:

  • Schema 访问:必须显式授权角色访问暴露的 schema:GRANT USAGE ON SCHEMA api TO webuser;

  • 表权限:按操作类型逐项授权,甚至可以细化到列(如UPDATE(message_body)只允许更新该列);

  • 行级安全(RLS):PostgREST 支持通过 RLS 实现每行可见性控制,例如聊天表只允许看到与自己相关消息的策略:

    CREATE POLICY chat_policy ON chat USING ((message_to = current_user) OR (message_from = current_user)) WITH CHECK (message_from = current_user)
  • 函数权限:默认函数对PUBLIC可执行,建议ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;后再显式GRANT EXECUTE;涉及私有对象的函数可用SECURITY DEFINER以函数属主身份执行;

  • 视图权限:视图以属主权限调用(类似SECURITY DEFINER),PostgreSQL 15+ 可用security_invoker选项改变该行为。

自定义校验可通过db-pre-request指定一个函数,在用户冒充之后、主查询之前执行,基于request.jwt.claims等 GUC 做任意检查并抛异常阻断请求:

db-pre-request = "public.check_user"
CREATE OR REPLACE FUNCTION check_user() RETURNS void AS $$ DECLARE email text := current_setting('request.jwt.claims', true)::json->>'email'; BEGIN IF email = 'evil.user@malicious.com' THEN RAISE EXCEPTION 'No, you are evil' USING HINT = 'Stop being so evil and maybe you can log in'; END IF; END $$ LANGUAGE plpgsql;

关于 JWT 安全的常见质疑

README 与 docs/references/auth.rst 还正面回应了三类针对 JWT 的常见批评:针对标准本身的alg=none攻击——PostgREST 实现不允许客户端在 HTTP 请求中指定签名算法,因此该攻击无效;针对已知漏洞库的问题——建议使用维护良好的实现;针对 JWT 用于 Web 会话的争论——PostgREST 建议 JWT 只用于认证/授权目的,Web 会话应使用基于 Cookie 的标准方案。

版本化:用数据库 Schema 做 API 版本管理

README 的 Versioning 小节 指出,一个健壮的长期 API 需要能够以多版本形态存在。PostgREST 通过数据库 Schema实现版本化:

PostgREST does versioning through database schemas. This allows you to expose tables and views without making the app brittle. Underlying tables can be superseded and hidden behind public facing views.

具体做法是:底层表可以被新版本取代,并通过对外可见的视图隐藏起来。比如v1v2两个 schema 分别承载两代 API,旧客户端继续访问v1,新客户端访问v2,底层表结构的演进对 API 消费者透明。

项目自身的版本策略(见 docs/index.rst)也值得了解:PostgREST 采用MAJOR.PATCH两段式版本号,MAJOR为功能版本(可引入新特性、废弃或移除已废弃特性),PATCH仅做修复与安全更新;自v14.0起只发布偶数MAJOR版本,奇数版本用于开发。废弃策略要求被废弃的特性至少保留一个MAJOR版本周期再移除。

自文档化:OpenAPI 与 HTTP 元数据

README 的 Self-documentation 小节 说明 PostgREST 使用OpenAPI 标准自动生成最新的 API 文档,可以配合 Swagger-UI 之类的工具渲染出可交互的演示文档,直接对线上 API 服务器发请求测试。

同时,项目也通过 HTTP 本身传递元数据:例如端点返回的行数由Range 头报告并被其限制(分页与计数细节见 docs/references/api/pagination_count.rst)。相关实现可参考 src/library/PostgREST/Response/OpenAPI.hs 与 src/library/PostgREST/RangeQuery.hs。

数据完整性:声明式约束与幂等 PUT

README 的 Data Integrity 小节 强调:与其依赖 ORM 和自定义命令式代码,不如把声明式约束直接放进数据库——这样任何应用(包括 API 服务器自身)都无法破坏数据。PostgREST 暴露的 HTTP 接口带有防止意外的安全措施,例如强制幂等的 PUT 请求(PUT按主键整体替换资源,重复提交不产生副作用,相关测试见 test/spec/Feature/Query/UpsertSpec.hs)。

架构速览:请求处理链路

从 docs/explanations/architecture.rst 的代码地图可以看清一次请求的完整链路,各模块源码均位于 src/library/PostgREST/ 下:

  1. Main.hs:程序入口,设置缓冲后进入 CLI;
  2. CLI.hs:解析命令行与配置;
  3. App.hs:组合各模块的主控制器;
  4. Auth.hs:JWT 认证;
  5. ApiRequest.hs:解析 URL 查询串、请求头与请求体,此阶段会拒绝无效的媒体类型或未知 HTTP 方法;
  6. Plan.hs:基于 Schema Cache 生成内部 AST,此阶段会拒绝不存在的嵌入资源等无效请求;
  7. Query.hs:生成参数化、预编译的 SQL,至此才从连接池取连接;
  8. SchemaCache.hs:维护数据库结构缓存;
  9. Config.hs:配置解析;
  10. Admin.hs:管理服务器(/ready健康检查即来自此模块);
  11. AppState/Reload.hs:监听数据库结构变更并触发缓存重载。

测试体系方面,test/io/configs/ 下存放了各类配置文件的测试样例(如 aliases.config、defaults.config),test/spec/Feature/ 下则按功能域组织了行为测试,例如 Query/AuthSpec.hs、Query/QuerySpec.hs,读者可结合这些测试深入理解各模块的实际行为约定。

结语

PostgREST 提供了一条"数据库即 API"的极简路径:把认证(JWT)、授权(数据库角色与 RLS)、校验(约束)全部下沉到数据库这一唯一事实来源,用 Haskell + Warp + Hasql 换取性能,用 OpenAPI 自动产出文档,用 Schema 承载版本化。它适合那些希望快速交付数据密集 API、同时保持严格数据完整性的团队——安装一个二进制文件、写一段配置,你的 PostgreSQL 就拥有了一个生产可用的 RESTful 端点。

【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 1:51:15

同城生活服务平台架构设计与运营实践

1. 同城生活服务平台的商业价值与市场定位在同城生活服务领域深耕多年后&#xff0c;我发现一个现象&#xff1a;用户越来越厌倦在十几个APP间来回切换找服务&#xff0c;商家也疲于维护多个平台的账号和订单。这正是我们打造一站式平台的核心出发点——用统一入口解决信息碎片…

作者头像 李华
网站建设 2026/9/11 1:50:41

智能门禁系统安装与调试全攻略:从接线规范到四大故障排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 1:50:08

树莓派Pico多线程看门狗:双核协作与故障自愈实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 1:49:51

C++动态分析实战:从内存泄漏到性能瓶颈的定位方法

1. 动态分析解决什么问题&#xff1a;从一次线上崩溃说起有段时间我一直在排查一个诡异的问题&#xff1a;某个C服务在客户机器上运行两三天后&#xff0c;内存占用会缓慢爬升&#xff0c;最终被系统杀掉。代码我翻来覆去读了好几遍&#xff0c;静态走查、code review、编译器告…

作者头像 李华
网站建设 2026/9/11 1:49:38

2026年3000-4000元平板选购指南:避开触控延迟与系统协同陷阱

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华