> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Adaptateurs personnalisés Créez un adaptateur personnalisé lorsque les adaptateurs de serveur prédéfinis (Hono, Express, Fastify, Koa) ne prennent pas en charge votre framework ou que vous avez des exigences particulières pour le traitement des requêtes et des réponses. Un adaptateur personnalisé assure la traduction entre les définitions de routes de Mastra et le système de routage de votre framework. Vous implémenterez des méthodes qui enregistrent le middleware, traitent les requêtes et envoient les réponses au moyen des API de votre framework. > **Info:** Utilisez l’un des adaptateurs de serveur prédéfinis suivants : > > - [@mastra/hono](https://mastra.zisheng.pro/fr/reference/server/hono-adapter) > - [@mastra/express](https://mastra.zisheng.pro/fr/reference/server/express-adapter) > - [@mastra/fastify](https://mastra.zisheng.pro/fr/reference/server/fastify-adapter) > - [@mastra/koa](https://mastra.zisheng.pro/fr/reference/server/koa-adapter) ## Classe abstraite La classe abstraite `MastraServer` du package `@mastra/server/server-adapter` constitue la base de tous les adaptateurs. Elle gère la logique d’enregistrement des routes, la validation des paramètres et d’autres fonctionnalités partagées. Votre adaptateur personnalisé étend cette classe et implémente les éléments propres au framework. La classe accepte trois paramètres de type qui représentent les types de votre framework : ```typescript import { MastraServer } from '@mastra/server/server-adapter' export class MyFrameworkServer extends MastraServer< // Your framework's app type (e.g., FastifyInstance) MyApp, // Your framework's request type (e.g., FastifyRequest) MyRequest, // Your framework's response type (e.g., FastifyReply) MyResponse > { // Implement abstract methods } ``` Ces paramètres garantissent la sûreté des types dans toute l’implémentation de votre adaptateur et permettent un typage correct lors de l’accès aux API propres au framework. ## Méthodes requises Vous devez implémenter ces six méthodes abstraites. Chacune gère une partie précise du cycle de vie de la requête, depuis l’association du contexte jusqu’à l’envoi des réponses. ### `registerContextMiddleware()` Cette méthode s’exécute en premier et associe le contexte Mastra à chaque requête entrante. Pour fonctionner, les gestionnaires de routes doivent accéder à l’instance Mastra, aux Tools et à d’autres éléments de contexte. La manière d’associer ce contexte dépend de votre framework : Express utilise `res.locals`, Hono utilise `c.set()`, et les autres frameworks suivent leurs propres modèles. ```typescript registerContextMiddleware(): void { this.app.use('*', (req, res, next) => { // Attach context to your framework's request/response res.locals.mastra = this.mastra; res.locals.requestContext = new RequestContext(); res.locals.tools = this.tools; res.locals.abortSignal = createAbortSignal(req); next(); }); } ``` Contexte à associer : | Clé | Type | Description | | ---------------- | ---------------------- | ------------------------------------------- | | `mastra` | `Mastra` | Instance Mastra | | `requestContext` | `RequestContext` | Map de contexte limitée à la requête | | `tools` | `Record` | Tools disponibles | | `abortSignal` | `AbortSignal` | Signal d’annulation de la requête | | `taskStore` | `InMemoryTaskStore` | Stockage des tâches A2A, s’il est configuré | ### `registerAuthMiddleware()` Enregistrez le middleware d’authentification et d’autorisation. Cette méthode doit vérifier si l’authentification est configurée dans l’instance Mastra et, dans le cas contraire, ignorer entièrement l’enregistrement. Lorsqu’elle est configurée, vous enregistrez généralement deux fonctions middleware : l’une pour l’authentification, qui valide les tokens et définit l’utilisateur, et l’autre pour l’autorisation, qui vérifie si l’utilisateur peut accéder à la ressource demandée. ```typescript registerAuthMiddleware(): void { const authConfig = this.mastra.getServer()?.auth; if (!authConfig) return; // Register authentication (validate token, set user) this.app.use('*', async (req, res, next) => { const token = extractToken(req); const user = await authConfig.authenticateToken?.(token, req); if (!user) { return res.status(401).json({ error: 'Unauthorized' }); } res.locals.user = user; next(); }); // Register authorization (check permissions) this.app.use('*', async (req, res, next) => { const allowed = await authConfig.authorize?.( req.path, req.method, res.locals.user, res ); if (!allowed) { return res.status(403).json({ error: 'Forbidden' }); } next(); }); } ``` ### `registerRoute()` Enregistrez une seule route dans votre framework. Cette méthode est appelée une fois pour chaque route Mastra lors de l’initialisation. Elle reçoit un objet `ServerRoute` contenant le chemin, la méthode HTTP, la fonction de gestion et les schémas Zod de validation. Votre implémentation doit relier ces éléments au système de routage de votre framework. ```typescript async registerRoute( app: MyApp, route: ServerRoute, { prefix }: { prefix?: string } ): Promise { const path = `${prefix || ''}${route.path}`; const method = route.method.toLowerCase(); app[method](path, async (req, res) => { try { // 1. Extract parameters const params = await this.getParams(route, req); // 2. Validate with Zod schemas const queryParams = await this.parseQueryParams(route, params.queryParams); const body = await this.parseBody(route, params.body); // 3. Build handler params const handlerParams = { ...params.urlParams, ...queryParams, ...(typeof body === 'object' ? body : {}), mastra: this.mastra, requestContext: res.locals.requestContext, tools: res.locals.tools, abortSignal: res.locals.abortSignal, taskStore: this.taskStore, }; // 4. Call handler const result = await route.handler(handlerParams); // 5. Send response return this.sendResponse(route, res, result); } catch (error) { const status = error.status ?? error.details?.status ?? 500; return res.status(status).json({ error: error.message }); } }); } ``` ### `getParams()` Extrayez de la requête entrante les paramètres d’URL, les paramètres de requête et le corps de la requête. Les frameworks exposent ces valeurs de différentes manières : Express utilise `req.params`, `req.query` et `req.body`, tandis que d’autres peuvent employer des noms de propriétés différents ou nécessiter des appels de méthodes. Cette méthode normalise l’extraction pour votre framework. ```typescript async getParams( route: ServerRoute, request: MyRequest ): Promise<{ urlParams: Record; queryParams: Record; body: unknown; }> { return { // From route path (e.g., :agentId) urlParams: request.params, // From URL query string queryParams: request.query, // From request body body: request.body, }; } ``` ### `sendResponse()` Renvoyez la réponse au client selon le type de réponse de la route. Les routes Mastra peuvent renvoyer différents types de réponses : du JSON pour la plupart des réponses d’API, des streams pour la génération des Agents et des types particuliers pour les transports MCP. Votre implémentation doit traiter chaque type de manière adaptée à votre framework. ```typescript async sendResponse( route: ServerRoute, response: MyResponse, result: unknown ): Promise { switch (route.responseType) { case 'json': return response.json(result); case 'stream': return this.stream(route, response, result); case 'datastream-response': // Return AI SDK Response directly return result; case 'mcp-http': // Handle MCP HTTP transport return this.handleMcpHttp(response, result); case 'mcp-sse': // Handle MCP SSE transport return this.handleMcpSse(response, result); default: return response.json(result); } } ``` ### `stream()` Gérez les réponses diffusées lors de la génération d’un Agent. Lorsqu’un Agent génère une réponse, il produit un stream de fragments qui doivent être envoyés au client dès qu’ils sont disponibles. Cette méthode lit le stream, applique éventuellement un masquage pour cacher les données sensibles, puis écrit les fragments dans la réponse au format approprié (SSE ou JSON délimité par des sauts de ligne). ```typescript async stream( route: ServerRoute, response: MyResponse, result: unknown ): Promise { const isSSE = route.streamFormat === 'sse'; // Set streaming headers based on format response.setHeader('Content-Type', isSSE ? 'text/event-stream' : 'text/plain'); response.setHeader('Transfer-Encoding', 'chunked'); const reader = result.fullStream.getReader(); try { while (true) { const { done, value } = await reader.read(); if (done) break; // Apply redaction if enabled const chunk = this.streamOptions.redact ? redactChunk(value) : value; // Format based on stream format if (isSSE) { response.write(`data: ${JSON.stringify(chunk)}\n\n`); } else { response.write(JSON.stringify(chunk) + '\x1E'); } } // Send completion marker (SSE uses data: [DONE], other formats use record separator) if (isSSE) { response.write('data: [DONE]\n\n'); } response.end(); } catch (error) { reader.cancel(); throw error; } } ``` ## Méthodes utilitaires La classe de base fournit des méthodes utilitaires que vous pouvez utiliser dans votre implémentation. Elles prennent en charge des tâches courantes, comme la validation des paramètres et l’enregistrement des routes, afin que vous n’ayez pas à les réimplémenter : | Méthode | Description | | ------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `parsePathParams(route, params)` | Valide les paramètres de chemin avec un schéma Zod | | `parseQueryParams(route, params)` | Valide les paramètres de requête avec un schéma Zod | | `parseBody(route, body)` | Valide le corps avec un schéma Zod | | `mergeRequestContext({ paramsRequestContext, bodyRequestContext })` | Fusionne les contextes de requête provenant de plusieurs sources | | `registerRoutes()` | Enregistre toutes les routes Mastra en appelant `registerRoute` pour chacune | | `registerOpenAPIRoute(app, config, { prefix })` | Enregistre le point de terminaison de la spécification OpenAPI | Les méthodes `parse*` utilisent les schémas Zod définis dans chaque route pour valider l’entrée et renvoyer des résultats typés. Si la validation échoue, elles lèvent une erreur qui détaille le problème rencontré. ## Constructor Le constructeur de votre adaptateur doit accepter les mêmes options que la classe de base et les transmettre à `super()`. Vous pouvez ajouter des options propres au framework si nécessaire : ```typescript constructor(options: { app: MyApp; mastra: Mastra; prefix?: string; openapiPath?: string; bodyLimitOptions?: BodyLimitOptions; streamOptions?: StreamOptions; customRouteAuthConfig?: Map; }) { super(options); } ``` Consultez la page [Adaptateurs de serveur](https://mastra.zisheng.pro/fr/docs/server/server-adapters) pour obtenir la documentation complète de chaque option. ## Exemple complet Voici une implémentation minimale qui présente toutes les méthodes requises. Elle utilise du pseudocode pour les parties propres au framework ; remplacez-le par les API réelles de votre framework : ```typescript import { MastraServer, ServerRoute } from '@mastra/server/server-adapter' import type { Mastra } from '@mastra/core' export class MyFrameworkServer extends MastraServer { constructor(options: { app: MyApp; mastra: Mastra; prefix?: string }) { super(options) } registerContextMiddleware(): void { this.app.use('*', (req, res, next) => { res.locals.mastra = this.mastra res.locals.requestContext = this.mergeRequestContext({ paramsRequestContext: req.query.requestContext, bodyRequestContext: req.body?.requestContext, }) res.locals.tools = this.tools ?? {} res.locals.abortSignal = createAbortSignal(req) next() }) } registerAuthMiddleware(): void { const authConfig = this.mastra.getServer()?.auth if (!authConfig) return // ... implement auth middleware } async registerRoute( app: MyApp, route: ServerRoute, { prefix }: { prefix?: string }, ): Promise { // ... implement route registration } async getParams(route: ServerRoute, request: MyRequest) { return { urlParams: request.params, queryParams: request.query, body: request.body, } } async sendResponse(route: ServerRoute, response: MyResponse, result: unknown) { if (route.responseType === 'stream') { return this.stream(route, response, result) } return response.json(result) } async stream(route: ServerRoute, response: MyResponse, result: unknown) { // ... implement streaming } } ``` ## Utilisation Une fois votre adaptateur implémenté, utilisez-le de la même manière que les adaptateurs fournis : ```typescript import { MyFrameworkServer } from './my-framework-adapter' import { mastra } from './mastra' const app = createMyFrameworkApp() const server = new MyFrameworkServer({ app, mastra }) await server.init() app.listen(4111) ``` > **Astuce:** Les implémentations existantes de [@mastra/hono](https://github.com/mastra-ai/mastra/blob/main/server-adapters/hono/src/index.ts) et [@mastra/express](https://github.com/mastra-ai/mastra/blob/main/server-adapters/express/src/index.ts) constituent de bonnes références pour créer votre adaptateur personnalisé. Elles montrent comment gérer les modèles propres au framework pour le stockage du contexte et l’enregistrement du middleware, ainsi que le traitement des réponses. > > Si vous souhaitez utiliser [Studio](https://mastra.zisheng.pro/fr/docs/studio/overview) avec votre adaptateur de serveur, utilisez [`mastra studio`](https://mastra.zisheng.pro/fr/reference/cli/mastra) afin de lancer uniquement l’interface de Studio. ## Voir aussi - [Adaptateurs de serveur](https://mastra.zisheng.pro/fr/docs/server/server-adapters) : présentation et concepts communs - [Adaptateur Hono](https://mastra.zisheng.pro/fr/reference/server/hono-adapter) : implémentation de référence - [Adaptateur Express](https://mastra.zisheng.pro/fr/reference/server/express-adapter) : implémentation de référence - [Référence de MastraServer](https://mastra.zisheng.pro/fr/reference/server/mastra-server) : référence complète de l’API - [Référence de createRoute()](https://mastra.zisheng.pro/fr/reference/server/create-route) : création de routes personnalisées avec typage sûr