路由自定义
通过自定义功能扩展你的路由器
您可以为以下路由器创建自定义配置以添加通过内置功能不可用的功能: GraphOS 路由器或者Apollo 路由器核心配置选项。例如,您可以针对每个传入请求进行外部调用以获取身份验证数据。
自定义类型
GraphOS 路由器支持以下自定义类型:
- Rhai 脚本
- Rhai 脚本语言 允许您通过挂钩路由器请求生命周期的不同阶段,直接将功能添加到您的原版 路由器 静态二进制文件。
- 外部协同处理(企业功能)
- 如果您组织拥有 GraphOS 企业计划,则您可以使用任何语言编写自定义请求处理代码。此代码可以与您的 路由器 或分开运行。
- 路由器通过 HTTP 调用您的自定义代码,并发送每个传入客户端请求的详细信息。
Apollo 路由器核心仅通过 Rhai 脚本 支持自定义。
由于 Rhai 脚本 更易于部署,如果您的情况需要使用它们,则建议使用它们。如果您的自定义需要执行以下任何操作(这些操作 Rhai 脚本不支持),请使用外部协同处理:
- 读取或写入磁盘
- 执行网络请求
- 使用特定语言或框架的库
请求生命周期
自定义在请求生命周期的特定点上介入,具体取决于您要执行的任务。每个点都由一个具有其自己的请求和响应对象的自定义服务表示。
每个服务都可以有一组插件。对于请求,路由器在服务之前执行插件。
对于响应,路由器在服务之后执行插件。
每个请求和响应对象都包含一个上下文
对象,它在整个过程中都会传递。每个请求的上下文
对象是唯一的。您可以使用它来在请求和响应之间存储特定于插件的零食息或用于在不同钩点之间通信。(插件可以在请求生命周期中的多个步骤中被调用。)
以下流程图展示了整个请求生命周期。第一个说明了从客户端到路由器各个部分,再到您的子图的请求路径。第二个说明了从您的子图返回客户端的响应路径。
请求路径
- 路由器在HTTP服务器上接收客户端请求。
- HTTP服务器将HTTP请求转换为一个包含HTTP头部和字节序列流的请求体
RouterRequest
。 - 路由器服务接收到
RouterRequest
。它处理自动持久查询(APQ),解析来自JSON的GraphQL请求,并以SupergraphRequest
将结果传递给supergraph服务。 - supergraph服务用
SupergraphRequest
中的GraphQL查询调用查询规划器。 - 查询规划器返回一个可高效执行查询的查询计划。
- supergraph服务使用由
SupergraphRequest
和查询计划组成的ExecutionRequest
调用执行服务。 - 对于查询计划中的每个提取节点,执行服务创建一个
SubgraphRequest
,然后调用相应的子图服务。 - 每个子图都有自己的子图服务,并且每个服务都可以有自己的子图插件配置。子图服务将
SubgraphRequest
转换为其子图的HTTP请求。该SubgraphRequest
包含以下内容:- 只读
SupergraphRequest
- HTTP头部
- 子图请求的操作类型(查询、突变或订阅)
- 作为请求体的GraphQL请求对象
- 只读
当您的子图提供响应后,响应将遵循以下路径。
响应路径
- 每个子图为子图服务提供一个HTTP响应。
- 每个子图服务创建一个
SubgraphResponse
,包含HTTP头和一个GraphQL响应。 - 一旦执行服务收到所有的子图响应,它会格式化GraphQL响应 —— 移除不需要的数据并传播空值 —— 然后将它作为ExecutionResponse发送回supergraph插件。
- The
SupergraphResponse
具有与ExecutionResponse
相同的内容。它包含头部和一个GraphQL响应流。这个流通常只包含一个元素(对于大多数查询而言)——如果查询使用了@defer
指令或订阅,它可能包含更多元素。 - 路由服务接受SupergraphResponse并将GraphQL响应序列化为JSON。
- The HTTP服务器将JSON作为HTTP响应发送给客户端。
请求和响应细节
出于简化的目的,先前的图示分别且顺序地显示了请求和响应两侧。实际上,一些请求和响应可能会同时且重复发生。
例如,SubgraphRequest
可以既并行也可以顺序地进行:一个子图的响应可能对另一个的SubgraphRequest
是必要的。(查询计划器决定哪些请求可以并行执行,哪些需要顺序执行。)
并行执行请求
顺序执行请求
此外,一些请求和响应可能会针对同一操作重复发生多次。例如,在使用订阅的情况下,子图会在数据更新时发送新的SubgraphResponse
。每个响应对象将穿过响应路径中的所有服务,并与你创建的任何自定义操作交互。
请求和响应缓冲
为了在流上正确执行并提供高性能,以下期望必须满足:
- 请求路径: 在
router_service
处理步骤之后不进行缓冲 - 响应路径: 不进行缓冲
一般来说,最好尽可能避免缓冲。如果需要的话,在router_service
步骤完成后在请求路径上进行缓冲是可以的。
如果以下内容适用,建议这样做:
- 修改路由器
- 创建原生Rust插件
- 创建自定义二进制文件