mcpField
A
apollo-router-plugin-creator

apollo-router-plugin-creator

github.com/apollographql开发1211.6k 次安装1 天前更新
代码仓库

关于 apollo-router-plugin-creator

这是用于为 Apollo Router 创建原生 Rust 插件的指南,说明如何选择请求生命周期钩子。它介绍请求与响应处理、验证、追踪、速率限制和超时的组合方式。

主要功能

  1. 01Router 生命周期服务钩子
  2. 02请求与响应转换
  3. 03同步与异步检查点
  4. 04追踪、速率限制与超时
  5. 05插件配置与注册

适用场景

  1. 01在 HTTP 层添加身份验证
  2. 02在规划前验证 GraphQL 请求
  3. 03控制查询计划的执行
  4. 04自定义子图调用的请求头

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/apollographql/skills --skill apollo-router-plugin-creator

安装后在 Claude Code 中输入/apollo-router-plugin-creator确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
examples.md
existing-plugins.md
service-hooks.md

详细介绍

Apollo Router 插件创建器

为 Apollo Router 创建原生 Rust 插件。

请求生命周期

┌────────┐             ┌────────────────┐                                   ┌────────────────────┐               ┌───────────────────┐       ┌─────────────────────┐
│ Client │             │ Router Service │                                   │ Supergraph Service │               │ Execution Service │       │ Subgraph Service(s) │
└────┬───┘             └────────┬───────┘                                   └──────────┬─────────┘               └─────────┬─────────┘       └──────────┬──────────┘
     │                          │                                                      │                                   │                            │
     │      Sends request       │                                                      │                                   │                            │
     │──────────────────────────▶                                                      │                                   │                            │
     │                          │                                                      │                                   │                            │
     │                          │  Converts raw HTTP request to GraphQL/JSON request   │                                   │                            │
     │                          │──────────────────────────────────────────────────────▶                                   │                            │
     │                          │                                                      │                                   │                            │
     │                          │                                                      │  Initiates query plan execution   │                            │
     │                          │                                                      │───────────────────────────────────▶                            │
     │                          │                                                      │                                   │                            │
     │                          │                                                      │                               ┌par [Initiates sub-operation]───────┐
     │                          │                                                      │                               │   │                            │   │
     │                          │                                                      │                               │   │  Initiates sub-operation   │   │
     │                          │                                                      │                               │   │────────────────────────────▶   │
     │                          │                                                      │                               │   │                            │   │
     │                          │                                                      │                               ├[Initiates sub-operation]╌╌╌╌╌╌╌╌╌╌╌┤
     │                          │                                                      │                               │   │                            │   │
     │                          │                                                      │                               │   │  Initiates sub-operation   │   │
     │                          │                                                      │                               │   │────────────────────────────▶   │
     │                          │                                                      │                               │   │                            │   │
     │                          │                                                      │                               ├[Initiates sub-operation]╌╌╌╌╌╌╌╌╌╌╌┤
     │                          │                                                      │                               │   │                            │   │
     │                          │                                                      │                               │   │  Initiates sub-operation   │   │
     │                          │                                                      │                               │   │────────────────────────────▶   │
     │                          │                                                      │                               │   │                            │   │
     │                          │                                                      │                               └────────────────────────────────────┘
     │                          │                                                      │                                   │                            │
     │                          │                                                      │  Assembles and returns response   │                            │
     │                          │                                                      ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│                            │
     │                          │                                                      │                                   │                            │
     │                          │            Returns GraphQL/JSON response             │                                   │                            │
     │                          ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│                                   │                            │
     │                          │                                                      │                                   │                            │
     │  Returns HTTP response   │                                                      │                                   │                            │
     ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│                                                      │                                   │                            │
     │                          │                                                      │                                   │                            │
┌────┴───┐             ┌────────┴───────┐                                   ┌──────────┴─────────┐               ┌─────────┴─────────┐       ┌──────────┴──────────┐
│ Client │             │ Router Service │                                   │ Supergraph Service │               │ Execution Service │       │ Subgraph Service(s) │
└────────┘             └────────────────┘                                   └────────────────────┘               └───────────────────┘       └─────────────────────┘

服务钩子

服务概览
服务说明
router_service在 HTTP 请求生命周期的最开始和最后运行。例如,JWT 身份验证在 RouterService 中执行。如果自定义逻辑需要与 HTTP 上下文和标头交互,请定义 router_service。它不支持访问 body 属性
supergraph_service在 GraphQL 请求生命周期的最开始和最后运行。如果自定义逻辑需要与 GraphQL 请求或 GraphQL 响应交互,请定义 supergraph_service。例如,可以添加对匿名查询的检查。
execution_service在查询计划生成后,负责启动其执行。如果自定义逻辑包含用于控制执行的逻辑(例如,想根据策略决策阻止特定查询),请定义 execution_service。
subgraph_service负责处理路由器与子图之间的通信。定义 subgraph_service 可配置此通信(例如,动态添加要传递给子图的 HTTP 标头)。其他服务每个客户端请求调用一次,而此服务则会针对解析客户端请求所需的每个子图请求调用一次。每次调用都会传入一个 subgraph 参数,用于指明对应子图的名称。

签名:

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
单独的钩子(Tower 层)

使用 ServiceBuilder 在任意服务中组合这些钩子:

钩子用途同步/异步
map_request(fn)在继续处理前转换请求同步
map_response(fn)在返回前转换响应同步
checkpoint(fn)验证/筛选,可短路处理同步
checkpoint_async(fn)异步验证,可短路处理异步
buffered()启用服务克隆(异步处理所需)-
instrument(span)在服务周围添加跟踪 span-
rate_limit(num, period)控制请求吞吐量-
timeout(duration)设置操作时限-
选择服务钩子

按所需数据选择:

  • 仅 HTTP 标头 → router_service
  • GraphQL 查询/变量 → supergraph_service
  • 查询计划 → execution_service
  • 控制各个子图 → subgraph_service

按时机选择:

  • GraphQL 解析前 → router_service 请求
  • 解析后、规划前 → supergraph_service 请求
  • 规划后、执行前 → execution_service 请求
  • 每次调用子图前后 → subgraph_service
  • 返回给客户端的最终响应 → router_service 响应

有关实现模式,请参阅 references/service-hooks.md。

快速入门

步骤 1:创建插件文件

创建新文件 src/plugins/my_plugin.rs,并添加所需的导入:

use std::ops::ControlFlow;
use apollo_router::plugin::{Plugin, PluginInit};
use apollo_router::register_plugin;
use apollo_router::services::{router, subgraph, supergraph};
use schemars::JsonSchema;
use serde::Deserialize;
use tower::{BoxError, ServiceBuilder, ServiceExt};

const PLUGIN_NAME: &str = "my_plugin";
步骤 2:定义配置结构体

每个插件都需要一个带有 Deserialize 和 JsonSchema 派生项的配置结构体。JsonSchema 可在编辑器中启用配置验证:

#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
struct MyPluginConfig {
  /// Enable the plugin
  enabled: bool,
  // Add other configuration fields as needed
}
步骤 3:定义插件结构体
#[derive(Debug)]
struct MyPlugin {
  configuration: MyPluginConfig,
}
步骤 4:实现插件 trait

实现 Plugin trait,并提供所需的 Config 类型和 new 构造函数:

#[async_trait::async_trait]
impl Plugin for MyPlugin {
  type Config = MyPluginConfig;

  async fn new(init: PluginInit<Self::Config>) -> Result<Self, BoxError> {
    Ok(MyPlugin { configuration: init.config })
  }

  // Add service hooks based on your needs (see "Choosing a Service Hook" section)
}
步骤 5:添加服务钩子

根据需求选择要挂接的服务,详情请参阅服务概览。

服务钩子示例:

fn supergraph_service(&self, service: supergraph::BoxService) -> supergraph::BoxService {
  if !self.configuration.enabled {
    return service;
  }

  ServiceBuilder::new()
    .map_request(|req| { /* transform request */ req })
    .map_response(|res| { /* transform response */ res })
    .service(service)
    .boxed()
}
步骤 6:注册插件

在插件文件底部,将插件注册到路由器:

register_plugin!("acme", "my_plugin", MyPlugin);
步骤 7:将模块添加到 mod.rs

在 src/plugins/mod.rs 中添加你的模块:

pub mod my_plugin;
步骤 8:在 YAML 中配置

在路由器配置中启用插件:

plugins:
  acme.my_plugin:
    enabled: true

常见模式

有关实现模式和代码示例,请参阅 references/service-hooks.md:

  • 启用/禁用模式
  • 请求/响应转换(map_request、map_response)
  • 检查点(提前返回/短路)
  • 在钩子之间传递上下文
  • 异步操作(checkpoint_async、buffered)
  • 错误响应构造器

示例

Apollo Router 示例

位于 Apollo Router 插件目录:

插件服务钩子模式描述
forbid_mutations.rsexecution_service检查点对查询计划实施简单门控
expose_query_plan.rsexecution + supergraph上下文传递多服务协调
cors.rsrouter_serviceHTTP 层在 HTTP 层处理 CORS
headers/subgraph_service层组合复杂的标头操作

完整的代码示例和测试模式,请参阅 references/examples.md。

前提条件

建议安装 rust-best-practices 技能,以便在开发路由器插件时编写符合 Rust 惯例的代码。如果已安装,请在生成或修改插件代码时遵循其中的最佳实践。

资源

评论

支持 Markdown