Zod nas Fronteiras
O TypeScript não consegue validar corpos HTTP, strings de consulta ou variáveis de ambiente em tempo de execução - esquemas Zod nas fronteiras do sistema transformam entrada desconhecida em dados tipados e confiáveis.
Busque em todas as páginas da documentação
O TypeScript não consegue validar corpos HTTP, strings de consulta ou variáveis de ambiente em tempo de execução - esquemas Zod nas fronteiras do sistema transformam entrada desconhecida em dados tipados e confiáveis.
import { z } from 'zod';
const EnvSchema = z.object({
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
});
export const env = EnvSchema.parse(process.env);const CreateUser = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
});
type CreateUser = z.infer<typeof CreateUser>;Quando usar isso:
process.envas MyType inseguros em req.bodyimport { z } from 'zod';
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
const EnvSchema = z.object({
PORT: z.coerce.number().default(3000),
});
const env = EnvSchema.parse(process.env);
const CreateItem = z.object({
name: z.string().min(1),
qty: z.number().int().positive(),
});
async function readJson(req: IncomingMessage): Promise<unknown> {
const chunks: Buffer[] = [];
for await (const chunk of req) chunks.push(chunk as Buffer);
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
}
function sendJson(res: ServerResponse, status: number, body: unknown): void {
res.writeHead(status, { 'content-type': 'application/json' });
res.end(JSON.stringify(body));
}
const server = createServer(async (req, res) => {
if (req.method === 'POST' && req.url === '/items') {
try {
const raw = await readJson(req);
const item = CreateItem.parse(raw);
sendJson(res, 201, { id: '1', ...item });
} catch (err) {
if (err instanceof z.ZodError) {
sendJson(res, 400, { error: 'validation_failed', issues: err.flatten() });
return;
}
throw err;
}
return;
}
sendJson(res, 404, { error: 'not_found' });
});
server.listen(env.PORT);O que isso demonstra:
parse lança ZodError em caso de falha - mapeie para 400, não 500z.coerce.number() lida com variáveis de ambiente string como "3000"z.infer deriva tipos TypeScript do mesmo esquema que em tempo de execuçãoflatten() produz erros em nível de campo seguros para clientesparse executa de forma síncrona - mantenha os esquemas modestos em caminhos quentes ou compile esquemas em cache.safeParse retorna { success, data | error } - estilo funcional sem try/catch.z.string().transform(s => s.trim())) executam após a validação - documente efeitos colaterais..refine()) expressam regras entre campos - confirmação de senha, intervalos de datas.| Fronteira | Localização do Esquema | Modo de Falha |
|---|---|---|
process.env | config/env.ts na importação | process.exit(1) |
| Corpo HTTP | Manipulador de rota / middleware | JSON 400 |
| SDK de Saída | Opcional - confie nos tipos do fornecedor | Registrar + circuit breaker |
import { z } from 'zod';
const IdParams = z.object({ id: z.string().uuid() });
// Padrão de middleware reutilizável
function parseParams<T extends z.ZodType>(schema: T, input: unknown): z.infer<T> {
return schema.parse(input);
}.parse em cargas úteis enormes repetidamente - compile uma vez, reutilize objetos de esquema. Correção: const Schema = z.object(...) no nível do módulo.flatten() ou um mapa de erros personalizado. Correção: registre o erro completo apenas no lado do servidor.z.infer, sem interface paralela.undefined falha em esquemas rigorosos. Correção: .optional(), .default(), ou documente as variáveis necessárias.z.string() para colunas HTML/JSON - validação != sanitização. Correção: escape na saída, SQL parametrizado.| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Fastify JSON Schema | Nativo do Fastify e de alto desempenho | Ecossistema Zod já é padrão |
| class-validator (NestJS) | DTOs com decoradores no NestJS 11 | Serviço Express mínimo |
| Valibot | Tamanho de pacote menor | Equipe já padronizada em Zod |
| Guardas manuais | Pequenos scripts internos | Qualquer entrada HTTP externa |
Os tipos são apagados no tempo de compilação. Atacantes enviam JSON malformado - apenas a validação em tempo de execução protege você.
parse lança exceções - bom com try/catch na camada HTTP. safeParse para validação em lote sem exceções.
z.object({ page: z.coerce.number().default(1) }).parse(req.query) - converte strings em números.
Sim - use ConfigModule com um factory Zod personalizado ou valide em main.ts antes de NestFactory.create.
CreateUser.partial() ou .pick({ name: true }) para DTOs de patch.
Publique esquemas de @acme/validation - o frontend usa o mesmo pacote para pré-validação do lado do cliente.
zod-to-openapi gera a especificação a partir de esquemas - única fonte para documentação e validação.
Zod é rápido o suficiente para a maioria das APIs - faça profiling antes de micro-otimizar; compile o env em cache na inicialização.
z.discriminatedUnion('type', [...]) para uniões discriminadas - bom para tipos de eventos de webhook.
Validação avançada entre campos com caminhos de issue personalizados - use com moderação para clareza.
Sim, na fronteira do repositório se o driver retornar unknown - não confie apenas nos tipos do ORM para colunas externas.
expect(() => Schema.parse(bad)).toThrow(z.ZodError) em node:test - fixtures inválidos orientados por tabela.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026