后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载PostGraphile 是 Graphile 生态中面向 PostgreSQL 的 GraphQL API 引擎它分析你的数据库结构自动生成完整、一致的 GraphQL Schema同时以「插件 预设preset」体系提供近乎无限的定制能力并依托 Grafast全计划执行引擎获得超越手写 resolver 的执行效率。读完本文你将掌握 PostGraphile 的自动化原理、smart tags 与extendSchema()两种主流定制方式、插件/预设系统的用法以及如何通过 CLI 或库函数快速启动一个生产级服务。本文以仓库内 postgraphile/postgraphile/README.md 为主体并结合 postgraphile/postgraphile/src 下的源码实现进行纵深讲解。一、PostGraphile 是什么只写带来价值的代码PostGraphile 的核心理念可以用一句话概括Focus on only writing the code that brings value.只编写带来价值的代码。如果你的主数据存储是 PostgreSQLPostGraphile 能帮助你以最小的精力构建出遵循最佳实践、结构良好、前端友好且高性能的 GraphQL API。它把「手写并长期维护一整套 schema」这种重复性劳动交给自动化管线处理让你把精力集中在真正有业务价值的代码上无缝扩展 schema加入自定义类型和字段这些字段可以执行 SQL 或 Node.js 代码用数据库权限治理暴露面快速、符合人体工程学、粒度细同时改善安全态势插件与预设系统把通用偏好应用到生成的 GraphQL schemasmart tags简单标签对单个数据库实体做微调——重命名、控制何时/如何暴露、改变类型/呈现/nullability、声明抽象类型interface/union、引入额外关系等inflection词形变化系统全面改造生成 schema 的命名风格官方推荐在数据库 schema 满足要求时使用graphile/simplify-inflection简化命名第三方插件为 schema 添加新功能与能力。二、工作原理从数据库到 GraphQL 的自动化管线PostGraphile 开箱即用out of the box它分析你的 PostgreSQL 数据库基于表、关系、函数、索引、权限以及你的配置构建出完整、一致的 GraphQL schema。这个 schema 是一个「活的基线」随数据库演化而演化你在这个基线上组合定制与扩展以最小精力雕刻出恰好满足客户端需求的 GraphQL API。从源码看整条管线的入口是 postgraphile/postgraphile/src/index.ts 中的postgraphile(preset)函数export function postgraphile( preset: GraphileConfig.Preset, ): PostGraphileInstance { const resolvedPreset resolvePreset(preset); // ... if (resolvedPreset.grafserv?.watch) { // 开启 watch 模式监控数据库 schema 变化并热更新 stopWatchingPromise watchSchema(preset, async (error, newParams) { ... }); } else { schemaResult makeSchema(preset); } // ... }关键点它接收一个GraphileConfig.Preset预设内部通过resolvePreset解析出最终配置如果配置了grafserv.watch则调用watchSchema监听数据库变化每次变化都会生成新的 schema 并热替换到正在运行的服务上server.setPreset(...)/server.setSchema(...)返回的PostGraphileInstance提供createServ(grafserv)、getSchemaResult()、getSchema()、getResolvedPreset()与release()等 API——这是以库方式集成 PostGraphile 的入口。三、执行效率Grafast全计划执行引擎PostGraphile 的执行层由 Graphile 生态中处于前沿的Grafast规划与执行引擎驱动。Grafast在真正执行之前会对整个 GraphQL 操作做完整的「计划planning」合并查询、消除 N1、避免后端数据欠取under-fetching与过取over-fetching因此 PostGraphile 的性能通常优于使用传统 GraphQL.js resolver 手写的 schema。这也是仓库被命名为 Crystal 的原因——它同时承载 Grafast、PostGraphile、pg-introspection、pg-sql2 等一整套相互配合的模块参见 README.md 的项目描述。在 postgraphile/postgraphile/package.json 中可以看到postgraphile包将grafast、grafserv、graphile-build、graphile-build-pg、dataplan/pg等作为工作区依赖与 peer 依赖并把它们通过./grafast、./grafserv、./utils等子路径重新导出供开发者在自定义逻辑中直接引用。四、一致性自动化 可微调PostGraphile 自动生成 API 的公共部分天然保证了整个 API 的一致性所有表都有风格统一的查询、变更与分页参数所有关系都遵循同样的命名与行为约定。与此同时插件与预设系统允许你对 schema 的每一个细节进行调整做到「自动化保底、定制无上限」。这套机制在 amber 预设 中体现得很直观PostGraphileAmberPreset通过extends组合了graphileBuildPreset与graphileBuildPgPreset并显式排列了一长串插件顺序QueryQueryPlugin、PgBasicsPlugin、PgTablesPlugin、PgRelationsPlugin、PgMutationCreatePlugin……注释说明这是为了与 PostGraphile V4 的插件顺序更兼容export const PostGraphileAmberPreset: GraphileConfig.Preset { extends: [orderedPlugins, graphileBuildPreset, graphileBuildPgPreset], plugins: [SwallowErrorsPlugin], };五、无锁定把 schema 导出为可执行代码PostGraphile 的设计哲学之一是不锁定用户。如果你有朝一日需要脱离 PostGraphile 自行维护可以把 schema导出为可执行代码exportSchema在不损失全计划执行性能优势的前提下接管后续维护。仓库内 graphile.config.ts 中就有一个真实的ExportSchemaPlugin示例它在schema.finalize钩子里调用exportSchema把生成结果写入exported-schema.mjsconst ExportSchemaPlugin: GraphileConfig.Plugin { name: ExportSchemaPlugin, version: 0.0.0, schema: { hooks: { finalize(schema) { exportSchema(schema, ${__dirname}/exported-schema.mjs, { mode: typeDefs, modules: { jsonwebtoken }, }).catch((e) console.error(e)); return schema; }, }, }, };导出能力的完整文档见 exporting-schema.md。六、可扩展性把 API 塑造成前端需要的样子GraphQL 是面向前端的因此大多数情况下你的 API 应该由客户端需求来塑造而不是数据库的简单 1:1 映射。PostGraphile 以最小精力帮你做到这一点很多业务领域对象在前端、后端与数据库之间天然对齐只需少量 tags 或辅助函数即可弥合细微差异对于不符合该模型的领域PostGraphile 从设计上就以可扩展性与可组合性为核心——从 introspection 到类型生成、再到添加分页参数几乎所有特性都是通过插件实现的。插件 API 极其强大灵活并且附带了辅助工厂函数helper factories为常见需求提供更符合人体工程学的 API。下面通过一个「购物车结算」的真实场景展示两种典型定制路径。6.1 路径一在数据库里用 smart tags 与 SQL 函数解决假设数据库只有products、prices、cart_items等底层表而前端需要subtotal、tax等派生字段价格还会随促销折扣或业务规则变化。这些计算不该由客户端实现而应该由 GraphQL schema 以强类型、文档完备的字段暴露出来。在 PostGraphile 中你可以直接在数据库层面处理-- 把 prices 表从 GraphQL schema 中隐藏 comment on table prices is behavior -*; -- 创建 Product.unitPrice 字段获取某个商品当前的价格 create function products_unit_price(p products) returns money as $$ select unit_price from prices where product_id p.product_id and now() valid_from and now() valid_until; $$ language sql stable; -- 为该字段补充文档说明 comment on function products_unit_price is The unit price at the current time, reflecting promotional discounts.;这段 SQL 会自动为Product类型添加unitPrice字段其语义是「按时间有效性查找商品当前单价」。这里假定时间段不会重叠如果可能重叠可以在查询里追加order by unit_price asc limit 1。这是 PostGraphile 最著名的「smart comments / smart tags」机制通过数据库注释comment以tag语法控制实体行为比如behavior -*隐藏整张表。仓库中 PgV4SmartTagsPlugin 即负责在 V4 兼容模式下解析这类标签。6.2 路径二用extendSchema()写 TypeScript 业务逻辑如果业务逻辑更复杂例如需要查询外部服务计算运费可以改用 schema 扩展schema extension。假设我们不写上面的数据库函数而是用 TypeScript 实现价格逻辑同时加入购物车「汇总」逻辑subtotal、shipping、tax、totalimport { extendSchema } from postgraphile/utils; import { constant, context, get } from postgraphile/grafast; import { batchSummarizeCart } from ./businessLogic/cart; export default extendSchema((build) { const { pgExecutor, pgResources: { cartItems, products, prices }, } build; return { typeDefs: /* GraphQL */ extend type Product { The unit price at the current time, reflecting promotional discounts. unitPrice: Money! } extend type Cart { summary: CartSummary } type CartSummary { subtotal: Money! shipping: Money! tax: Money! total: Money! } , plans: { Product: { unitPrice($item) { // 找到相关价格 const productId $item.get(product_id); const $prices prices.find({ productId: $productId }); $prices.where(sqlnow() valid_from and now() valid_until); // 恰好一行取回并返回单价 return $prices.single().get(unit_price); }, }, Cart: { summary($cart) { const $cartId $cart.get(id); return loadOne($cartId, batchSummarizeCart); }, }, // CartSummary 不需要 plan resolver可以使用默认行为。 }, }; });要点解读extendSchema()来自postgraphile/utils转发自graphile-utils可以添加调用任意 Node.js 业务逻辑的自定义类型和字段并能与 Node.js 能通信的任何数据源集成plans中的函数是plan resolver计划解析器它们不直接取值而是构建数据获取的「计划」。$item.get(product_id)拿到当前行对象中的列prices.find(...)发起一次数据查找$prices.single()断言单行结果这种方式同样可用于数据库 schema 做破坏性变更时维持向后兼容。extendSchema只是众多插件辅助函数之一你还可以用插件体系做更多事情把 schema 变成你自己的。6.3 批量加载loadOne/loadMany与 DataLoader 风格回调上面的batchSummarizeCart是典型的 DataLoader 风格回调。业务逻辑可以用任何你喜欢的方式实现、可以做任何 Node.js 能做的事官方通常假定你使用 DataLoader 风格的回调实际上你可以直接把自己的 DataLoader 回调用在loadOne/loadMany上以实现批量加载。而相比原生 DataLoaderloadOne()/loadMany()步骤还有若干增强优势。一个完整的批量汇总实现如下// businessLogic/cart.ts import { context } from postgraphile/grafast; export const batchSummarizeCart { // 计划在 loader 中拿到 GraphQL context shared: () context(), // cartIds 是一批 Cart 标识shared 是运行时 GraphQL context整批共享 async load(cartIds, { shared }) { const carts await batchGetCartInfo(shared, cartIds); const cartsWithShipping await batchCalculateShippingCosts(carts); const cartsWithTax await batchCalculateTax(cartsWithShipping); return cartIds.map((cartId) { const cartInfo cartsWithTax.find((c) c.cart_id cartId); const { subtotal, shipping, tax } cartInfo; const total subtotal shipping tax; return { subtotal, shipping, tax, total }; }); }, }; /** 来自数据库的 Cart 信息 */ interface CartInfo { cart_id: number; shipping_address: Address; subtotal: number; mass: number; } async function batchGetCartInfo(shared, cartIds) { // 跨所有 cart 做单次数据库查询如果需要也可以用你的 ORM const result await shared.withPgClient(shared.pgSettings, (db) db.queryCartInfo({ text: select carts.id as cart_id, to_json(carts.shipping_address) as shipping_address, sum(cart_items.quantity * prices.unit_amount) as subtotal, sum(cart_items.quantity * products.mass) as mass from carts inner join cart_items on (cart_items.cart_id carts.id) inner join prices on ( prices.product_id cart_items.product_id and now() valid_from and now() valid_to ) where carts.id any($1::int[]) group by carts.id , values: [cartIds], }), ); return result.rows; } interface CartInfoWithShipping extends CartInfo { shipping: number; } async function batchCalculateShippingCosts(carts: CartInfo[]) { // TODO: 根据每个 cart 的质量和地址计算运费 return carts.map((cart) ({ ...cart, shipping: 500 })); } interface CartInfoWithShippingAndTax extends CartInfoWithShipping { shipping: number; } async function batchCalculateTax(carts: CartInfoWithShipping[]) { // TODO: 按区域更新为正确的税率 const TAX_PERCENTAGE 20; return carts.map((cart) ({ ...cart, tax: ((cart.subtotal cart.shipping) * TAX_PERCENTAGE) / 100, })); }这里shared.withPgClient来自运行时 context负责在整批请求间共享同一个数据库客户端load回调把cartIds数组一次性地映射为结果数组——这正是 N1 问题的根治方式。七、插件与预设系统全局偏好的载体PostGraphile 把配置组织为「预设preset」——一个可extends继承、由插件列表与各配置项组成的对象。除了上面的 amber 基础预设仓库内 postgraphile/postgraphile/src/presets 还提供了多个开箱即用的预设预设文件作用amber.ts推荐的基础预设组合 graphile-build / graphile-build-pg 默认插件并重排 V4 兼容顺序v4.tsV4 兼容预设makeV4Preset(options)支持simpleCollections、jwtPgTypeIdentifier、dynamicJson、graphiql、ignoreRBAC、simpleSubscriptions等 V4 风格选项relay.ts实验性 Relay 预设把id字段名改为row_id、引入nodeId相关行为等lazy-jwt.ts懒加载 JWT 预设从Authorization: Bearer头解析 JWT 并把 claims 写入pgSettings.jwt.claims.*minify.ts实验性压缩预设导出 schema 前剥离文档与弃用信息、精简 registry其中 v4.ts 是迁移用户的重点关注对象。它提供的V4Options完整覆盖了 V4 时代的主流配置项例如simpleCollections: only | both | omit——控制生成列表list还是连接connection集合classicIds、dynamicJson、jwtPgTypeIdentifier、jwtSecretdisableDefaultMutations、ignoreRBAC、ignoreIndexesgraphqlRoute、graphiqlRoute、graphiql、bodySizeLimit、allowExplainsubscriptions/simpleSubscriptions、watchPg、retryOnInitFail等。值得注意的是V4 的enableQueryBatching在 V5 已被显式禁止类型为never源码注释解释了原因查询批处理未成为 GraphQL-over-HTTP 规范的组成部分HTTP2 服务器普及后其需求大幅下降且增量交付stream/defer会让批处理在网络层产生不必要的复杂度——官方建议改用 HTTP2。另外defaultRole也不再支持需要改用preset.grafast.context回调。八、快速上手CLI 与库两种姿势8.1 CLI 方式一条命令启动服务postgraphile包提供了 CLI 入口bin指向dist/cli-run.js。仓库中 cli.ts 完整定义了命令行参数参数别名说明--connection-cPostgreSQL 连接字符串--superuser-connection-S用于安装 watch fixtures 的连接字符串需要超级用户权限--schema-s要暴露为 GraphQL 的数据库 schema或逗号分隔的多个 schema默认public--watch-w监听模式监控数据库 schema 变化--port-pHTTP 服务端口--host-nHTTP 服务绑定主机--subscriptions若 schema 支持则通过 websocket 启用 GraphQL subscriptions--config-C配置文件路径--preset-P逗号分隔的预设列表--allow-explain-e允许访客查看每个 GraphQL 操作对应的计划 / SQL 查询等官方示例命令postgraphile --preset postgraphile/presets/amber \ --connection postgres://localhost:5432/dbname \ --schema public \ --allow-explain从 cli.ts 的实现可以看到CLI 会依次加载命令行指定的预设与配置文件 → 用makePgService构造pgServices→ 应用port/host/websockets/watch/explain等选项 → 调用postgraphile(config)构建实例 → 通过grafserv/node创建 HTTP 服务。如果既不指定--preset也没有graphile.config.jsCLI 会提示加上推荐的--preset postgraphile/presets/amber若不指定--connection则退出并提示连接字符串格式。8.2 库方式把 PostGraphile 嵌入你的 Node.js 服务也可以直接用postgraphile(preset)编程式集成返回的实例再通过createServ(grafserv)挂载到任意 grafserv 支持的服务器上Express、Fastify、Koa、Hono、Lambda 等import { postgraphile } from postgraphile; import { grafserv } from postgraphile/grafserv/node; const pgl postgraphile({ extends: [PostGraphileAmberPreset], pgServices: [makePgService({ connectionString: postgres:///mydb })], }); const serv pgl.createServ(grafserv); const server createServer(); serv.addTo(server); server.listen(5678);以库方式集成时makePgService来自postgraphile/adaptors/pg服务端配置放在preset.grafserv如port、graphqlPath、websockets、graphqlOverGET、maskError执行引擎配置放在preset.grafast如context、explain。仓库自带的 graphile.config.ts 是一个信息量极大的参考实现其中包含了pgServices通过makePgService配置connectionString、schemas与pubsub: true启用 LISTEN/NOTIFY 客户端grafserv配置port: 5678、graphqlPath: /graphql、websockets: true、graphqlOverGET: true、maskError错误掩码以及持久化操作目录grafast.context回调注入pgSettings、number、mol等运行时上下文通过extends同时组合PostGraphileAmberPreset、makeV4Preset({...})、PostGraphileRelayPreset、PgLazyJWTPreset并追加大量自定义插件StreamDefer、extendSchema 扩展、wrapPlans 包装、Ruru HTML 定制、schema 导出等。8.3 配置graphile.config.js 优先PostGraphile 的配置体系基于graphile-config你可以把预设写进graphile.config.js或.tsCLI 与库方式都会自动加载。完整的配置与预设文档见 postgraphile/website/postgraphile/config 目录从 V4 迁移的详细指引见 migrating-from-v4。九、测试与验证庞大的自动化测试矩阵PostGraphile 的可靠性由仓库内规模庞大的测试矩阵背书。postgraphile/postgraphile/tests包含queries/与mutations/目录下成百上千组测试每组都配有.graphql查询、.json5期望结果、.sql数据库夹具、.mermaid计划图并支持EXPORT_SCHEMAtypeDefs/graphql-js两种导出模式运行schema/目录下 70 余个 TypeScript 测试文件覆盖 schema 构建细节subscriptions/与helpers.ts、kitchen-sink-*.sql等共享夹具。这些测试既验证了 schema 生成与查询执行的正确性也验证了 schema 导出scripts/test-schema-exports.mjs与操作导出test:operations-exports的一致性。对于想要深入理解 PostGraphile 行为或贡献代码的开发者这是绝佳的学习材料。十、总结如果你的后端以 PostgreSQL 作为主数据存储、并且使用常规的关系型 schemaPostGraphile 是让你的项目以创纪录速度跑起来的最佳途径之一得益于消除后端欠取与过取问题的全计划执行它还能以极少的资源与复杂度支撑起显著的规模。PostGraphile 的核心价值可以归结为四点自动化从数据库 introspection 直接生成完整、一致的 GraphQL schema与数据库演化保持同步高性能Grafast计划执行引擎通常优于传统手写 resolver 方案可定制smart tags、extendSchema()、插件与预设系统、inflection 命名系统层层递进满足从微调到重构的一切需求无锁定schema 可导出为可执行代码随时接管维护而不损失性能优势。停止手写样板代码让 PostGraphile 帮你迭代得更快——从 quick-start-guide.mdx 开始连接你的数据库几分钟内就能得到一个可运行、可扩展、生产可用的 GraphQL API。赞分享后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载相关推荐PostGraphile 入门指南从 PostgreSQL 自动生成高性能 GraphQL API 的架构与实践PostGraphile 入门指南从 PostgreSQL 自动生成高性能 GraphQL API 的架构与实践 导读 本文基于 Crystal 仓库中 Po后端API网关PostGraphile实战指南从PostgreSQL到GraphQL API的自动化转换PostGraphile实战指南从PostgreSQL到GraphQL API的自动化转换 本文深入探讨PostGraphile的架构设计、工作原理及其在生产后端API网关Graphile Build PG 深度解析从 PostgreSQL 内省到高性能 GraphQL Schema 的自动化生成Graphile Build PG 深度解析从 PostgreSQL 内省到高性能 GraphQL Schema 的自动化生成 graphile build后端API网关创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
8x8x8 LED立方体:多路复用与74HC595驱动实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:45:31
EB Tresos离线激活全链路解析:硬件指纹、activation.xml与.lic签发机制 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:45:24
4针PWM风扇调速电路设计:从MOSFET驱动到PCB布局 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:45:24
有了 AI 问数,还需要数据大屏吗? “上周哪个区域的延期项目最多?”如果这个问题可以直接问 AI,再沿着答案追问原因,团队还要不要做一块数据大屏?
这个问题不能只看哪种界面更新。数字化团队真正要判断的是:眼前缺的是一个回答,还是一份能够… · 2026/9/24 13:37:06
零基础三步写出稳拿offer的简历 直接进入正题吧,我发现找工作最难的一步是写简历,一份能让你拿到面试的简历,就是把你做过的事情,翻译成目标公司需要的能力。第一步:把你要找的工作、想去的公司的JD复制下来,拆解JD,圈出高频词… · 2026/9/24 13:37:00
openchamber 1.4.1:Ghostty 终端渲染与 Bun PTY 加速、多模型对比实战解析 AI Agent人工智能代码智能体交互助手 【免费下载链接】openchamber Agentic Development Environment based on OpenCode AI agent 项目地址: https://gitcode.com/gh_mirrors/op/openchamber 点击查看 免费下载 本篇技术指南以 changelog/1.4.1.md(版本… · 2026/9/24 13:36:47
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44