> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # 커스텀 API 경로 기본적으로 Mastra는 서버를 통해 등록된 Agent와 Workflow를 자동으로 노출합니다. 추가 동작을 위해 자체 HTTP 경로를 정의할 수 있습니다. 경로는 `@mastra/core/server`의 `registerApiRoute()` 헬퍼로 정의합니다. 경로를 `Mastra` 인스턴스와 같은 파일에 둘 수도 있지만, 분리하면 구성을 간결하게 유지하는 데 도움이 됩니다. ```typescript import { Mastra } from '@mastra/core' import { registerApiRoute } from '@mastra/core/server' export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute('/my-custom-route', { method: 'GET', handler: async c => { const mastra = c.get('mastra') const agent = await mastra.getAgent('my-agent') return c.json({ message: 'Custom route' }) }, }), ], }, }) ``` 등록되면 서버 루트에서 사용자 지정 경로에 액세스할 수 있습니다. 예를 들어: ```bash curl http://localhost:4111/my-custom-route ``` 각 경로의 핸들러는 Hono `Context`를 받습니다. 핸들러 내에서 `Mastra` 인스턴스에 접근하여 Agent와 Workflow를 가져오거나 호출할 수 있습니다. ## 미들웨어 경로별 미들웨어를 추가하려면 `registerApiRoute()`를 호출할 때 `middleware` 배열을 사용하세요. ```typescript import { Mastra } from '@mastra/core' import { registerApiRoute } from '@mastra/core/server' export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute('/my-custom-route', { method: 'GET', middleware: [ async (c, next) => { console.log(`${c.req.method} ${c.req.url}`) await next() }, ], handler: async c => { return c.json({ message: 'Custom route with middleware' }) }, }), ], }, }) ``` ## OpenAPI 문서 사용자 지정 경로에는 Mastra 서버 경로와 함께 Swagger UI에 표시되는 OpenAPI 메타데이터를 포함할 수 있습니다. 사용자 지정 경로와 기본 제공 경로가 모두 나열되는 `/api/openapi.json`에서 OpenAPI 사양에 접근할 수 있습니다. 표준 OpenAPI 작업 필드가 포함된 `openapi` 옵션을 전달하세요. ```typescript import { Mastra } from '@mastra/core' import { registerApiRoute } from '@mastra/core/server' import { z } from 'zod' export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute('/items/:itemId', { method: 'GET', openapi: { summary: 'Get item by ID', description: 'Retrieves a single item by its unique identifier', tags: ['Items'], parameters: [ { name: 'itemId', in: 'path', required: true, description: 'The item ID', schema: { type: 'string' }, }, ], responses: { 200: { description: 'Item found', content: { 'application/json': { schema: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' }, }, }, }, }, }, 404: { description: 'Item not found', }, }, }, handler: async c => { const itemId = c.req.param('itemId') return c.json({ id: itemId, name: 'Example Item' }) }, }), ], }, }) ``` ### Zod 스키마 사용 OpenAPI 문서를 생성할 때 `openapi` 구성의 Zod 스키마는 JSON Schema로 변환됩니다. ```typescript import { Mastra } from '@mastra/core' import { registerApiRoute } from '@mastra/core/server' import { z } from 'zod' const ItemSchema = z.object({ id: z.string(), name: z.string(), price: z.number(), }) const CreateItemSchema = z.object({ name: z.string().min(1), price: z.number().positive(), }) export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute('/items', { method: 'POST', openapi: { summary: 'Create a new item', tags: ['Items'], requestBody: { required: true, content: { 'application/json': { schema: CreateItemSchema, }, }, }, responses: { 201: { description: 'Item created', content: { 'application/json': { schema: ItemSchema, }, }, }, }, }, handler: async c => { const body = await c.req.json() return c.json({ id: 'new-id', ...body }, 201) }, }), ], }, }) ``` ### Swagger UI에서 보기 개발 모드(`mastra dev`) 또는 빌드 옵션에서 `swaggerUI: true`로 설정한 경우 사용자 지정 경로가 `/swagger-ui`의 Swagger UI에 표시됩니다. ```typescript export const mastra = new Mastra({ server: { build: { swaggerUI: true, // Enable in production builds }, apiRoutes: [ // Your routes... ], }, }) ``` ## 입증 Mastra 서버에 인증이 구성되면 사용자 정의 API 경로에는 기본적으로 인증이 필요합니다. 경로를 공개적으로 접근 가능하게 하려면 다음을 설정하십시오.`requiresAuth: false`: ```typescript import { Mastra } from '@mastra/core' import { registerApiRoute } from '@mastra/core/server' import { MastraJwtAuth } from '@mastra/auth' export const mastra = new Mastra({ server: { auth: new MastraJwtAuth({ secret: process.env.MASTRA_JWT_SECRET, }), apiRoutes: [ // Protected route (default behavior) registerApiRoute('/protected-data', { method: 'GET', handler: async c => { // Access authenticated user from request context const user = c.get('requestContext').get('user') return c.json({ message: 'Authenticated user', user }) }, }), // Public route (no authentication required) registerApiRoute('/webhooks/github', { method: 'POST', requiresAuth: false, // Explicitly opt out of authentication handler: async c => { const payload = await c.req.json() // Process webhook without authentication return c.json({ received: true }) }, }), ], }, }) ``` ### 인증 동작 - **구성된 인증 없음**: 모든 경로(기본 제공 및 사용자 지정)가 공개됩니다. - **인증이 구성됨**: - Mastra 제공 노선(`/api/agents/*`, `/api/workflows/*`, etc.) require authentication - 커스텀 경로에는 기본적으로 인증이 필요합니다. - 커스텀 경로는 다음을 통해 선택 해제할 수 있습니다.`requiresAuth: false` ### 사용자 정보에 접근하기 요청이 인증되면 요청 컨텍스트에서 사용자 개체를 사용할 수 있습니다. ```typescript registerApiRoute('/user-profile', { method: 'GET', handler: async c => { const requestContext = c.get('requestContext') const user = requestContext.get('user') return c.json({ user }) }, }) ``` 인증 공급자에 대한 자세한 내용은 다음을 참조하세요.[Auth documentation](https://mastra.zisheng.pro/ko/docs/server/auth). ## 클라이언트 연결 해제 후 계속 생성 [`chatRoute()`](https://mastra.zisheng.pro/ko/reference/ai-sdk/chat-route) 같은 기본 제공 스트리밍 헬퍼는 수신 요청의 `AbortSignal`을 `agent.stream()`에 전달합니다. 브라우저 연결이 끊어질 때 Model 호출을 취소해야 하는 경우 적절한 기본 동작입니다. 클라이언트 연결이 끊어질 때 중지되어야 하는 사용자 지정 스트리밍 경로에서는 `c.req.raw.signal`을 `agent.stream()` 같은 장기 실행 작업에 전달하세요. Mastra의 Node 기반 어댑터는 클라이언트 연결이 종료되면 사용자 지정 경로에서 스트리밍되는 `Response` 본문 읽기도 중지합니다. 클라이언트 연결 끊김으로 인해 발생한 것이 아닌 스트리밍 응답 본문 오류는 어댑터의 일반 오류 처리를 통해 계속 전파됩니다. Hono에서 연결 끊김 동작은 호스트 런타임이 연결 종료를 `request.signal`에 전달하는지에 따라 달라집니다. ```typescript registerApiRoute('/stream', { method: 'GET', handler: async c => { const stream = await agent.stream(prompt, { abortSignal: c.req.raw.signal, }) return stream.toTextStreamResponse() }, }) ``` 클라이언트 연결이 끊어진 후에도 서버에서 최종 응답을 계속 생성하고 유지하려면 기본 `MastraModelOutput`을 중심으로 사용자 지정 경로를 구축하세요. `c.req.raw.signal`을 전달하지 않고 Agent 스트림을 시작한 다음, 백그라운드에서 `consumeStream()`을 호출하여 서버 측에서 생성을 계속하세요. ```typescript import { createUIMessageStream, createUIMessageStreamResponse, InferUIMessageChunk, UIMessage, } from 'ai' import { toAISdkStream } from '@mastra/ai-sdk' import { Mastra } from '@mastra/core' import { registerApiRoute } from '@mastra/core/server' export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute('/chat/persist/:agentId', { method: 'POST', handler: async c => { const { messages, memory } = await c.req.json() const mastra = c.get('mastra') const agent = mastra.getAgent(c.req.param('agentId')) const stream = await agent.stream(messages, { memory, // Do not pass c.req.raw.signal if this route should keep running // after the client disconnects. }) void stream.consumeStream().catch(error => { mastra.getLogger()?.error('Background stream consumption failed', { error }) }) const uiStream = createUIMessageStream({ originalMessages: messages, execute: async ({ writer }) => { for await (const part of toAISdkStream(stream, { from: 'agent' })) { writer.write(part as InferUIMessageChunk) } }, }) return createUIMessageStreamResponse({ stream: uiStream }) }, }), ], }, }) ``` > **노트:** HTTP 클라이언트가 사라진 후에도 의도적으로 작업을 계속하려는 경우에만 이 패턴을 사용하세요. 연결이 끊어지면 생성을 취소하려면 계속 `chatRoute()`를 사용하거나 요청의 `AbortSignal`을 직접 전달하세요. ## 관련된 - [RegisterApiRoute() 참조](https://mastra.zisheng.pro/ko/reference/server/register-api-route): 전체 API 참조 - [서버 미들웨어](https://mastra.zisheng.pro/ko/docs/server/middleware): 글로벌 미들웨어 구성 - [마스트라 서버](https://mastra.zisheng.pro/ko/docs/server/mastra-server): 서버 구성 옵션