写作与公文
为 Apollo Router 编写原生 Rust…
在需要创建、修改 Apollo Router 原生 Rust 插件或添加 router/supergraph/execution/subgraph 服务钩子时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
为 Apollo Router 编写原生特定
解决思路
- 理解请求生命周期:客户端 → Router Service(将原始 HTTP 请求转换为 GraphQL/JSON 请求)→ Supergraph Service(启动查询计划执行)→ Execution Service(并行发起子操作)→ Subgraph Service(s)(组装并返回响应,再逐层回传 GraphQL/JSON 响应与 HTTP 响应)。
- 根据所需数据选择服务钩子:仅需 HTTP headers 用 router_service;需要 GraphQL query/variables 用 supergraph_service;需要 query plan 用 execution_service;需要按子图控制用 subgraph_service。
- 根据时机选择服务钩子:GraphQL 解析前用 router_service request;解析后、规划前用 supergraph_service request;规划后、执行前用 execution_service request;每次子图调用前后用 subgraph_service;返回客户端的最终响应用 router_service response。
- 使用 ServiceBuilder 组合单个钩子:map_request(fn) 同步转换请求;map_response(fn) 同步转换响应;checkpoint(fn) 同步校验/过滤并可短路;checkpoint_async(fn) 异步校验并可短路;buffered() 启用服务克隆(异步所需);instrument(span) 添加 tracing span;rate_limit(num, period) 控制请求吞吐;timeout(duration) 设置操作时限。
- 创建插件文件 src/plugins/my_plugin.rs,导入所需模块:std::ops::ControlFlow、apollo_router::plugin::{Plugin, PluginInit}、apollo_router::register_plugin、apollo_router::services::{router, subgraph, supergraph}、schemars::JsonSchema、serde::Deserialize、tower::{BoxError, ServiceBuilder, ServiceExt},并定义 const PLUGIN_NAME。
- 定义配置结构体,派生 Debug、Clone、Default、Deserialize、JsonSchema(JsonSchema 用于编辑器中的配置校验),按需添加配置字段(如 enabled: bool)。
- 定义插件结构体,派生 Debug,包含 configuration 字段。
- 实现 Plugin trait:指定 type Config = MyPluginConfig;实现 async fn new(init: PluginInit<Self::Config>) -> Result<Self, BoxError>,返回包含 init.config 的插件实例。
- 按需求添加服务钩子,签名分别为:fn router_service(&self, service: router::BoxService) -> router::BoxService;fn supergraph_service(&self, service: supergraph::BoxService) -> supergraph::BoxService;fn execution_service(&self, service: execution::BoxService) -> execution::BoxService;fn subgraph_service(&self, name: &str, service: subgraph::BoxService) -> subgraph::BoxService。
- 在钩子实现中可先判断配置(如 if !self.configuration.enabled { return service; }),再用 ServiceBuilder::new().map_request(...).map_response(...).service(service).boxed() 包装服务。
- 在插件文件底部用 register_plugin!("acme", "my_plugin", MyPlugin); 注册插件。
- 在 src/plugins/mod.rs 中添加 pub mod my_plugin;。
- 在 router 配置 YAML 中启用插件:plugins: acme.my_plugin: enabled: true。
- 参考常见模式实现:启用/禁用模式、请求/响应转换(map_request、map_response)、checkpoint 提前返回/短路、钩子间 Context 传递、异步操作(checkpoint_async、buffered)、错误响应构建器。
- 参考 Apollo Router 现有插件示例:forbid_mutations.rs(execution_service + checkpoint,对 query plan 做简单门控)、expose_query_plan.rs(execution + supergraph,多服务协作与 Context 传递)、cors.rs(router_service,HTTP 层 CORS 处理)、headers/(subgraph_service,复杂 header 操作的层组合)。
- 建议安装 rust-best-practices skill,在生成或修改插件代码时遵循其惯用 Rust 最佳实践。
适用边界 · 注意事项
- 需要访问 HTTP body 的场景不要用 router_service,它不支持访问 body 属性。
- 需要 GraphQL 请求/响应或 query plan 的场景不要用 router_service,应改用 supergraph_service 或 execution_service。
- 需要按子图分别控制通信的场景不要用其他服务钩子,应使用 subgraph_service(它按每个子图请求调用一次,并传入子图名称)。