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
- references/service-hooks.md - Implémentations détaillées des service hooks
- references/existing-plugins.md - Index des plugins existants
- references/examples.md - Exemples de code complets et motifs de test
- Apollo Router plugins: https://github.com/apollographql/router/tree/dev/apollo-router/src/plugins