Validação de entrada
Quando você define um schema input, cada requisição é validada antes de executar o handler. Se a validação falhar, o handler não é executado e um 400 é retornado:
{
"error": "Validation failed",
"details": [
{
"path": ["email"],
"message": "Invalid email",
"code": "invalid_string"
}
]
}
import { define, z } from "@jelou/functions";
export default define({
name: "create-ticket",
description: "Creates a support ticket from WhatsApp",
input: z.object({
name: z.string().min(1).describe("Customer name"),
email: z.string().email().describe("Contact email"),
subject: z.string().max(200).describe("Ticket subject"),
priority: z.enum(["low", "medium", "high"]).default("medium"),
}),
output: z.object({
ticketId: z.string(),
status: z.string(),
}),
handler: async (input, ctx) => {
ctx.log("Creating ticket", { customer: input.name, priority: input.priority });
return { ticketId: "TKT-2024-0042", status: "open" };
},
});
Tipos suportados
Você pode usar qualquer tipo Zod dentro de z.object():
input: z.object({
name: z.string().min(1),
age: z.number().int().positive(),
email: z.string().email(),
active: z.boolean().default(true),
role: z.enum(["admin", "user", "guest"]),
tags: z.array(z.string()).optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
})
Coerção em requisições GET
Para requisições GET, os parâmetros de query são strings. Use z.coerce para converter tipos automaticamente:
import { define, z } from "@jelou/functions";
export default define({
name: "search-orders",
description: "Search orders by status",
input: z.object({
q: z.string(),
limit: z.coerce.number().default(10),
page: z.coerce.number().default(1),
active: z.coerce.boolean().default(true),
}),
handler: async (input, ctx) => {
ctx.log("Searching", { q: input.q, limit: input.limit });
return { results: [], total: 0 };
},
});
curl "https://search-orders.fn.jelou.ai/?q=pending&limit=5&page=2"
Anotações .describe()
Use .describe() em cada campo para documentar os parâmetros. Essas descrições aparecem automaticamente no schema MCP, ajudando os agentes de IA a entender como usar sua função:
input: z.object({
phone: z.string().min(10).describe("Phone number with country code, e.g.: 593987654321"),
includeHistory: z.boolean().default(false).describe("Whether to include the conversation history"),
})
Validação de saída
Quando você define um schema output, o valor retornado pelo handler é validado após a execução. Se não corresponder:
- Um aviso é registrado no log
- A resposta é enviada normalmente com status
200
A validação de saída nunca bloqueia a resposta. É uma ferramenta de desenvolvimento para detectar inconsistências.
output: z.object({
name: z.string(),
balance: z.number(),
})
Se o handler retornar { name: "Maria", balance: "150" } (balance como string), você verá um aviso nos logs, mas o cliente recebe a resposta sem alterações.
Cada erro no array details contém:
| Campo | Tipo | Descrição |
|---|
path | string[] | Caminho até o campo com o erro, ex.: ["email"] ou ["address", "city"] |
message | string | Mensagem de erro legível por humanos |
code | string | Código de erro Zod (ex.: invalid_string, too_small, invalid_enum_value) |
{
"error": "Validation failed",
"details": [
{
"path": ["name"],
"message": "String must contain at least 1 character(s)",
"code": "too_small"
},
{
"path": ["priority"],
"message": "Invalid enum value. Expected 'low' | 'medium' | 'high', received 'urgent'",
"code": "invalid_enum_value"
}
]
}