apollo-router-plugin-creator

Guide pour rédiger des plugins natifs Rust pour Apollo Router. Utilisez cette compétence quand : (1) les utilisateurs veulent créer un nouveau plugin router, (2) les utilisateurs veulent ajouter des hooks de service (`router_service`, `supergraph_service`, `execution_service`, `subgraph_service`), (3) les utilisateurs veulent modifier un plugin router existant, (4) les utilisateurs ont besoin de comprendre les patterns de plugins router ou le cycle de vie des requêtes. (5) se déclenche sur des requêtes comme « create a new plugin », « add a router plugin », « modify the X plugin » ou « add subgraph_service hook ».

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

Créateur de plugin Apollo Router

Créez des plugins Rust natifs pour Apollo Router.

Cycle de vie des requêtes

┌────────┐             ┌────────────────┐                                   ┌────────────────────┐               ┌───────────────────┐       ┌─────────────────────┐
│ 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

Vue d'ensemble des services

Service Description
router_service S'exécute au tout début et à la toute fin du cycle de vie de la requête HTTP. Par exemple, l'authentification JWT est effectuée au sein de RouterService. Définissez router_service si votre personnalisation doit interagir avec le contexte HTTP et les en-têtes. Elle ne supporte pas l'accès à la propriété body.
supergraph_service S'exécute au tout début et à la toute fin du cycle de vie de la requête GraphQL. Définissez supergraph_service si votre personnalisation doit interagir avec la requête GraphQL ou la réponse GraphQL. Par exemple, vous pouvez ajouter une vérification pour les requêtes anonymes.
execution_service Gère l'initiation de l'exécution d'un plan de requête après sa génération. Définissez execution_service si votre personnalisation inclut une logique pour gouverner l'exécution (par exemple, si vous voulez bloquer une requête particulière en fonction d'une décision de politique).
subgraph_service Gère la communication entre le routeur et vos subgraphes. Définissez subgraph_service pour configurer cette communication (par exemple, pour ajouter dynamiquement des en-têtes HTTP à passer à un subgraphe). Alors que les autres services sont appelés une fois par requête client, ce service est appelé une fois par requête subgraphe requise pour résoudre la requête du client. Chaque appel reçoit un paramètre subgraph qui indique le nom du subgraphe correspondant.

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

Hooks individuels (Couches Tower)

Utilisez ServiceBuilder pour composer ces hooks dans n'importe quel service :

Hook Objectif Sync/Async
map_request(fn) Transformer la requête avant de procéder Sync
map_response(fn) Transformer la réponse avant de la retourner Sync
checkpoint(fn) Valider/filtrer, peut court-circuiter Sync
checkpoint_async(fn) Validation async, peut court-circuiter Async
buffered() Activer le clonage de service (nécessaire pour async) -
instrument(span) Ajouter une plage de traçage autour du service -
rate_limit(num, period) Contrôler le débit des requêtes -
timeout(duration) Définir la limite de temps d'opération -

Choisir un Service Hook

Par données nécessaires :

  • En-têtes HTTP uniquement → router_service
  • Requête/variables GraphQL → supergraph_service
  • Plan de requête → execution_service
  • Contrôle par subgraphe → subgraph_service

Par timing :

  • Avant l'analyse GraphQL → requête router_service
  • Après analyse, avant planification → requête supergraph_service
  • Après planification, avant exécution → requête execution_service
  • Avant/après chaque appel subgraphe → subgraph_service
  • Réponse finale au client → réponse router_service

Voir references/service-hooks.md pour les motifs d'implémentation.

Démarrage rapide

Étape 1 : Créer le fichier de plugin

Créez un nouveau fichier src/plugins/my_plugin.rs avec les imports requis :

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";

Étape 2 : Définir la structure de configuration

Chaque plugin a besoin d'une structure de configuration avec les dérivations Deserialize et JsonSchema. JsonSchema active la validation de configuration dans les éditeurs :

#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
struct MyPluginConfig {
  /// Enable the plugin
  enabled: bool,
  // Add other configuration fields as needed
}

Étape 3 : Définir la structure du plugin

#[derive(Debug)]
struct MyPlugin {
  configuration: MyPluginConfig,
}

Étape 4 : Implémenter le trait Plugin

Implémentez le trait Plugin avec le type Config requis et le constructeur 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)
}

Étape 5 : Ajouter les Service Hooks

Choisissez le(s) service(s) à utiliser en fonction de vos besoins. Voir Vue d'ensemble des services pour plus de détails.

Exemple de service hook :

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()
}

Étape 6 : Enregistrer le plugin

À la fin de votre fichier de plugin, enregistrez-le auprès du routeur :

register_plugin!("acme", "my_plugin", MyPlugin);

Étape 7 : Ajouter le module à mod.rs

Dans src/plugins/mod.rs, ajoutez votre module :

pub mod my_plugin;

Étape 8 : Configurer en YAML

Activez votre plugin dans la configuration du routeur :

plugins:
  acme.my_plugin:
    enabled: true

Motifs courants

Pour les motifs d'implémentation et les exemples de code, voir references/service-hooks.md :

  • Motif d'activation/désactivation
  • Transformation de requête/réponse (map_request, map_response)
  • Checkpoint (retour anticipé/court-circuit)
  • Passage de contexte entre les hooks
  • Opérations async (checkpoint_async, buffered)
  • Générateurs de réponse d'erreur

Exemples

Exemples d'Apollo Router

Situés dans le répertoire des plugins Apollo Router :

Plugin Service Hook Motif Description
forbid_mutations.rs execution_service checkpoint Simple gate on query plan
expose_query_plan.rs execution + supergraph Context passing Multi-service coordination
cors.rs router_service HTTP layer CORS handling at HTTP level
headers/ subgraph_service Layer composition Complex header manipulation

Pour les exemples de code complets et les motifs de test, voir references/examples.md.

Prérequis

Il est conseillé d'avoir la compétence rust-best-practices installée pour écrire du code Rust idiomatique lors du développement de plugins de routeur. Si elle est installée, respectez ces bonnes pratiques lors de la génération ou de la modification du code de plugin.

Ressources

Skills similaires