跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

Custom API routes

默认情况下,Mastra 会自动通过服务器暴露已注册的 agent 和工作流。如需额外行为,你可以定义自己的 HTTP 路由。

路由通过 @mastra/core/server 提供的辅助函数 registerApiRoute() 注册。路由可以与 Mastra 实例放在同一文件中,但将它们分开有助于保持配置简洁。

src/mastra/index.ts
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' })
},
}),
],
},
})

注册后,自定义路由可从服务器根路径访问。例如:

curl http://localhost:4111/my-custom-route

每个路由的处理器接收 Hono Context。在处理器中,你可以访问 Mastra 实例来获取或调用 agent 和工作流。

Schema 验证
Schema 验证的直接链接

在 apiRoutes 中使用 createRoute(),通过 Zod 解析并验证路径和查询参数以及请求体。这些 schema 还会推断处理器参数并生成 OpenAPI 元数据。

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { createRoute } from '@mastra/server/server-adapter'
import { z } from 'zod'

const createItemRoute = createRoute({
method: 'POST',
path: '/items',
responseType: 'json',
bodySchema: z.object({
name: z.string().min(1),
}),
responseSchema: z.object({
id: z.string(),
name: z.string(),
}),
handler: async ({ name }) => ({
id: crypto.randomUUID(),
name,
}),
})

export const mastra = new Mastra({
server: {
apiRoutes: [createItemRoute],
},
})

默认情况下,验证失败时 Mastra 返回 400 响应。onValidationError 回调可以覆盖状态码和响应体。验证后的值和 Mastra 服务器上下文会直接传给处理器。

中间件
中间件的直接链接

要为特定路由添加中间件,请在调用 registerApiRoute() 时传入 middleware 数组。

src/mastra/index.ts
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 文档
OpenAPI 文档的直接链接

自定义路由可以包含 OpenAPI 元数据,以便与 Mastra 服务器路由一起显示在 Swagger UI 中。你可以在 /api/openapi.json 访问 OpenAPI 规范,其中列出了自定义路由和内置路由。传入带有标准 OpenAPI 操作字段的 openapi 选项。

src/mastra/index.ts
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 schema
使用 Zod schema的直接链接

生成 OpenAPI 文档时,openapi 配置中的 Zod schema 会被转换为 JSON Schema:

src/mastra/index.ts
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 中查看
在 Swagger UI 中查看的直接链接

在开发模式下(mastra dev)运行,或在构建选项中设置 swaggerUI: true 时,你的自定义路由会出现在 /swagger-ui 的 Swagger UI 中。

export const mastra = new Mastra({
server: {
build: {
swaggerUI: true, // Enable in production builds
},
apiRoutes: [
// Your routes...
],
},
})

身份验证
身份验证的直接链接

在 Mastra 服务器上配置身份验证后,自定义 API 路由默认需要身份验证。要使路由公开可访问,请设置 requiresAuth: false:

src/mastra/index.ts
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 })
},
}),
],
},
})

身份验证行为
身份验证行为的直接链接

  • 未配置 auth:所有路由(内置和自定义)都是公开的
  • 已配置 auth:
    • Mastra 提供的路由(/api/agents/*、/api/workflows/* 等)需要身份验证
    • 自定义路由默认需要身份验证
    • 自定义路由可以通过 requiresAuth: false 选择退出

访问用户信息
访问用户信息的直接链接

当请求通过身份验证后,用户对象在请求上下文中可用:

registerApiRoute('/user-profile', {
method: 'GET',
handler: async c => {
const requestContext = c.get('requestContext')
const user = requestContext.get('user')

return c.json({ user })
},
})

有关身份验证提供商的更多信息,请参阅 Auth 文档。

客户端断开连接后继续生成
客户端断开连接后继续生成的直接链接

诸如 chatRoute() 的内置流式辅助函数会将传入请求的 AbortSignal 转发给 agent.stream()。当浏览器断开连接应取消模型调用时,这是正确的默认行为。

对于应在客户端断开连接时停止的自定义流式路由,请将 c.req.raw.signal 传给 agent.stream() 等长时间运行的工作。Mastra 基于 Node 的适配器在客户端连接关闭时也会停止读取自定义路由的流式 Response 正文。并非由客户端断开连接引起的流式响应正文错误仍会通过适配器的正常错误处理传播。在 Hono 中,断开连接行为取决于宿主运行时是否将连接关闭转发到 request.signal。

src/mastra/index.ts
registerApiRoute('/stream', {
method: 'GET',
handler: async c => {
const stream = await agent.stream(prompt, {
abortSignal: c.req.raw.signal,
})

return stream.toTextStreamResponse()
},
})

如果你希望服务器在客户端断开连接后仍继续生成并持久化最终响应,请围绕底层 MastraModelOutput 构建自定义路由。启动 agent 流时不转发 c.req.raw.signal,然后在后台调用 consumeStream(),使生成在服务器端继续。

src/mastra/index.ts
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<UIMessage>)
}
},
})

return createUIMessageStreamResponse({ stream: uiStream })
},
}),
],
},
})
备注

仅当你有意希望在 HTTP 客户端断开后继续工作时才使用此模式。如果你希望断开连接取消生成,请继续使用 chatRoute() 或自行转发请求的 AbortSignal。

相关内容
相关内容的直接链接