Overview
Handler functions process HTTP requests in custom API routes. They receive a Hono context object with request information and helper methods for crafting responses.
Handler Type
type Handler<Variables, Path, PathParams> = (
c: Context<{ Variables: Variables }, Path, PathParams>
) => Response | Promise<Response>
Context Object
The context object provides access to the request, Mastra instance, and response helpers.
Properties
The HTTP request object with methods for accessing headers, params, query, and body
Environment variables and runtime context
Context Variables (via c.get())
The Mastra instance, accessible via c.get('mastra')
Request context for dependency injection, accessible via c.get('requestContext')
Request Methods
req.param
c.req.param(name: string): string
c.req.param(): Record<string, string>
Gets URL path parameters.
// Route: /users/:id
const id = c.req.param('id');
// Or get all params
const params = c.req.param();
req.query
c.req.query(name: string): string | undefined
c.req.query(): Record<string, string>
Gets URL query parameters.
// URL: /search?q=hello&limit=10
const query = c.req.query('q'); // 'hello'
const limit = c.req.query('limit'); // '10'
// Or get all queries
const queries = c.req.query();
c.req.header(name: string): string | undefined
c.req.header(): Record<string, string>
Gets request headers.
const auth = c.req.header('authorization');
const contentType = c.req.header('content-type');
// Or get all headers
const headers = c.req.header();
req.json
c.req.json<T>(): Promise<T>
Parses request body as JSON.
const body = await c.req.json<{ name: string; email: string }>();
console.log(body.name, body.email);
req.text
c.req.text(): Promise<string>
Gets request body as text.
const text = await c.req.text();
c.req.formData(): Promise<FormData>
Parses request body as FormData.
const formData = await c.req.formData();
const file = formData.get('file');
Response Methods
json
c.json<T>(object: T, status?: number, headers?: Record<string, string>): Response
Returns a JSON response.
return c.json({ message: 'Success', data: result }, 200);
return c.json({ error: 'Not found' }, 404);
return c.json({ data }, 200, {
'X-Custom-Header': 'value'
});
text
c.text(text: string, status?: number, headers?: Record<string, string>): Response
Returns a plain text response.
return c.text('Hello, World!');
return c.text('Not Found', 404);
html
c.html(html: string, status?: number, headers?: Record<string, string>): Response
Returns an HTML response.
return c.html('<h1>Welcome</h1>');
redirect
c.redirect(url: string, status?: number): Response
Redirects to a URL.
return c.redirect('/login', 302);
return c.redirect('https://example.com', 301);
notFound
Returns a 404 Not Found response.
Context Methods
get
Gets a context variable.
const mastra = c.get('mastra');
const requestContext = c.get('requestContext');
set
c.set<T>(key: string, value: T): void
Sets a context variable.
c.set('user', authenticatedUser);
var
Access to all context variables.
const { mastra, requestContext } = c.var;
Example Handlers
Basic Handler
import { registerApiRoute } from '@mastra/core';
registerApiRoute('/hello', {
method: 'GET',
handler: async (c) => {
return c.json({ message: 'Hello, World!' });
}
});
Path Parameters
registerApiRoute('/users/:id', {
method: 'GET',
handler: async (c) => {
const id = c.req.param('id');
const mastra = c.get('mastra');
const storage = mastra.getStorage();
// Fetch user from storage
const user = await storage.getUser(id);
if (!user) {
return c.json({ error: 'User not found' }, 404);
}
return c.json({ user });
}
});
Query Parameters
registerApiRoute('/search', {
method: 'GET',
handler: async (c) => {
const query = c.req.query('q');
const limit = parseInt(c.req.query('limit') || '10');
const offset = parseInt(c.req.query('offset') || '0');
// Perform search
const results = await searchDatabase(query, { limit, offset });
return c.json({ query, results, limit, offset });
}
});
POST with JSON Body
registerApiRoute('/users', {
method: 'POST',
handler: async (c) => {
const body = await c.req.json<{
name: string;
email: string;
}>();
// Validate
if (!body.name || !body.email) {
return c.json({ error: 'Missing required fields' }, 400);
}
// Save to storage
const mastra = c.get('mastra');
const storage = mastra.getStorage();
const user = await storage.createUser(body);
return c.json({ user }, 201);
}
});
Using Agents
registerApiRoute('/chat', {
method: 'POST',
handler: async (c) => {
const { message, threadId } = await c.req.json<{
message: string;
threadId?: string;
}>();
const mastra = c.get('mastra');
const agent = mastra.getAgent('assistant');
const response = await agent.generate(message, {
memory: threadId ? {
thread: threadId,
resource: 'user-123'
} : undefined
});
return c.json({
response: response.text,
threadId: response.threadId
});
}
});
Streaming Response
registerApiRoute('/stream', {
method: 'POST',
handler: async (c) => {
const { message } = await c.req.json<{ message: string }>();
const mastra = c.get('mastra');
const agent = mastra.getAgent('assistant');
const stream = await agent.stream(message);
return new Response(stream.textStream);
}
});
Error Handling
registerApiRoute('/data/:id', {
method: 'GET',
handler: async (c) => {
try {
const id = c.req.param('id');
const mastra = c.get('mastra');
const storage = mastra.getStorage();
const data = await storage.getData(id);
if (!data) {
return c.json({ error: 'Data not found' }, 404);
}
return c.json({ data });
} catch (error) {
console.error('Error fetching data:', error);
return c.json({
error: 'Internal server error',
message: error instanceof Error ? error.message : 'Unknown error'
}, 500);
}
}
});
Authentication Check
registerApiRoute('/protected', {
method: 'GET',
handler: async (c) => {
const authHeader = c.req.header('authorization');
if (!authHeader?.startsWith('Bearer ')) {
return c.json({ error: 'Unauthorized' }, 401);
}
const token = authHeader.substring(7);
const user = await verifyToken(token);
if (!user) {
return c.json({ error: 'Invalid token' }, 401);
}
return c.json({ message: 'Protected data', user });
}
});
File Upload
registerApiRoute('/upload', {
method: 'POST',
handler: async (c) => {
const formData = await c.req.formData();
const file = formData.get('file') as File;
if (!file) {
return c.json({ error: 'No file provided' }, 400);
}
// Process file
const buffer = await file.arrayBuffer();
const content = Buffer.from(buffer);
// Save to storage
const mastra = c.get('mastra');
const fileId = await saveFile(content, file.name);
return c.json({
message: 'File uploaded successfully',
fileId,
filename: file.name,
size: file.size
});
}
});
Request Context
registerApiRoute('/context', {
method: 'GET',
handler: async (c) => {
const requestContext = c.get('requestContext');
// Set values in request context
requestContext.set('userId', 'user-123');
requestContext.set('role', 'admin');
// These values are available to agents, tools, etc.
const mastra = c.get('mastra');
const agent = mastra.getAgent('assistant');
const response = await agent.generate('Hello', {
requestContext
});
return c.json({ response: response.text });
}
});