Labsco
apollographql logo

apollo-router-plugin-creator

β˜… 91

by apollographql Β· part of apollographql/skills

Guide for writing Apollo Router native Rust plugins. Use this skill when: (1) users want to create a new router plugin, (2) users want to add service hooks (router_service, supergraph_service, execution_service, subgraph_service), (3) users want to modify an existing router plugin, (4) users need to understand router plugin patterns or the request lifecycle. (5) triggers on requests like "create a new plugin", "add a router plugin", "modify the X plugin", or "add subgraph_service hook".

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeQuick setup
πŸ”Œ This skill ships inside the Apollo GraphQL Skills plugin β€” install the plugin and you also get an MCP server.

This is the playbook your agent receives when the skill activates β€” you don't need to read it to use the skill, but it's here to audit before installing.

Apollo Router Plugin Creator

Create native Rust plugins for Apollo Router.

Request Lifecycle

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 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) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Service Hooks

Service Overview

ServiceDescription
router_serviceRuns at the very beginning and very end of the HTTP request lifecycle.For example, JWT authentication is performed within the RouterService.Define router_service if your customization needs to interact with HTTP context and headers. It doesn't support access to the body property
supergraph_serviceRuns at the very beginning and very end of the GraphQL request lifecycle.Define supergraph_service if your customization needs to interact with the GraphQL request or the GraphQL response. For example, you can add a check for anonymous queries.
execution_serviceHandles initiating the execution of a query plan after it's been generated.Define execution_service if your customization includes logic to govern execution (for example, if you want to block a particular query based on a policy decision).
subgraph_serviceHandles communication between the router and your subgraphs.Define subgraph_service to configure this communication (for example, to dynamically add HTTP headers to pass to a subgraph).Whereas other services are called once per client request, this service is called once per subgraph request that's required to resolve the client's request. Each call is passed a subgraph parameter that indicates the name of the corresponding subgraph.

Signatures:

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

Individual Hooks (Tower Layers)

Use ServiceBuilder to compose these hooks within any service:

HookPurposeSync/Async
map_request(fn)Transform request before proceedingSync
map_response(fn)Transform response before returningSync
checkpoint(fn)Validate/filter, can short-circuitSync
checkpoint_async(fn)Async validation, can short-circuitAsync
buffered()Enable service cloning (needed for async)-
instrument(span)Add tracing span around service-
rate_limit(num, period)Control request throughput-
timeout(duration)Set operation time limit-

Choosing a Service Hook

By data needed:

  • HTTP headers only β†’ router_service
  • GraphQL query/variables β†’ supergraph_service
  • Query plan β†’ execution_service
  • Per-subgraph control β†’ subgraph_service

By timing:

  • Before GraphQL parsing β†’ router_service request
  • After parsing, before planning β†’ supergraph_service request
  • After planning, before execution β†’ execution_service request
  • Before/after each subgraph call β†’ subgraph_service
  • Final response to client β†’ router_service response

See references/service-hooks.md for implementation patterns.

Common Patterns

For implementation patterns and code examples, see references/service-hooks.md:

  • Enable/disable pattern
  • Request/response transformation (map_request, map_response)
  • Checkpoint (early return/short-circuit)
  • Context passing between hooks
  • Async operations (checkpoint_async, buffered)
  • Error response builders

Examples

Apollo Router Examples

Located in the Apollo Router plugins directory:

PluginService HookPatternDescription
forbid_mutations.rsexecution_servicecheckpointSimple gate on query plan
expose_query_plan.rsexecution + supergraphContext passingMulti-service coordination
cors.rsrouter_serviceHTTP layerCORS handling at HTTP level
headers/subgraph_serviceLayer compositionComplex header manipulation

For full code examples and testing patterns, see references/examples.md.

Resources