Pare de criar APIs REST do zero em 2025
Descubra a abordagem de APIs orientadas por esquema, que substitui o código repetitivo por contratos declarativos.
Se você é um desenvolvedor back-end ou full-stack, conhece o ritual: uma nova funcionalidade requer um novo endpoint de API, e começa a cerimônia de boilerplate: definir a rota, escrever o controlador, validar a entrada, lidar com erros e atualizar a documentação.

Esse processo não é apenas tedioso — é frágil. Cada definição ou conversão adicional é uma chance para um bug silencioso: tipos incompatíveis, documentação desatualizada ou validação esquecida. Os desenvolvedores aceitaram isso como o custo da confiabilidade.
Mas em 2025, é hora de desafiar essa suposição. Construir APIs manualmente é um anti-padrão. O ecossistema moderno oferece algo melhor: um paradigma orientado a esquemas que substitui a configuração repetitiva por contratos declarativos.
Este artigo desconstrói o método antigo, introduz o modelo orientado por esquemas e mostra por que escrever APIs REST do zero não faz mais sentido.
Configuração clássica de endpoint REST
Vamos ilustrar o problema construindo um simples endpoint POST /users da maneira “clássica”, usando Express e yup.
import * as yup from 'yup';
interface CreateUserRequest {
username: string;
email: string;
age: number;
}
const createUserSchema = yup.object({
username: yup.string().min(3).required(),
email: yup.string().email().required(),
age: yup.number().positive().integer().required(),
});
Imediatamente, definimos a mesma estrutura duas vezes — violando o princípio DRY e criando problemas de sincronização.
Agora, o próprio endpoint:
import express, { Request, Response, NextFunction } from 'express';
import * as yup from 'yup';
const app = express();
app.use(express.json());
const validate = (schema: yup.AnyObjectSchema) =>
async (req: Request, res: Response, next: NextFunction) => {
try {
await schema.validate(req.body);
next();
} catch (err) {
res.status(400).json({ type: 'validation_error', message: err.message });
}
};
app.post('/users', validate(createUserSchema), (req, res) => {
const userData = req.body as CreateUserRequest;
try {
const newUser = { id: Date.now(), ...userData };
res.status(201).json(newUser);
} catch {
res.status(500).json({ message: 'Internal server error' });
}
});
Repetimos a mesma cerimônia: esquemas duplicados, middleware de validação manual, casting de tipos explícito e bagunça com try/catch.
Para piorar, ainda precisaríamos atualizar manualmente nossa documentação OpenAPI — uma terceira fonte de verdade sujeita a desatualizações.
A solução orientada por esquemas
A alternativa é um modelo declarativo: defina seu contrato uma vez e deixe seu framework lidar com roteamento, validação e documentação.
Vamos reconstruir o mesmo endpoint usando tRPC com Zod como nossa única fonte de verdade.
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.create();
const createUserSchema = z.object({
username: z.string().min(3),
email: z.string().email(),
age: z.number().positive().int(),
});
export const appRouter = t.router({
createUser: t.procedure
.input(createUserSchema)
.mutation(({ input }) => {
const newUser = { id: Date.now(), ...input };
return newUser;
}),
});
export type AppRouter = typeof appRouter;
Veja o que mudou:
- Um esquema, uma verdade. Os tipos são inferidos automaticamente do Zod.
- Sem middleware. A validação está embutida.
- Sem casting de tipos. Entradas e saídas são fortemente tipadas.
- Sem
try/catch. Erros são tratados graciosamente pelo framework.
O resultado: iteração mais rápida, menos bugs e código auto-documentado.
Frameworks que adotam APIs orientadas por esquemas
Essa mudança não se limita ao tRPC — é uma tendência mais ampla na indústria. Veja como três outros frameworks implementam princípios semelhantes.
Hono: Padrões da Web encontram segurança de tipos
import { Hono } from 'hono';
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';
const app = new Hono();
const createUserSchema = z.object({
username: z.string().min(3),
email: z.string().email(),
age: z.number().positive().int(),
});
app.post('/users', zValidator('json', createUserSchema), (c) => {
const userData = c.req.valid('json');
const newUser = { id: Date.now(), ...userData };
return c.json(newUser, 201);
});
Hono moderniza a sintaxe no estilo Express com middleware de validação embutido — configuração mínima, segurança total de tipos.
Fastify: Desempenho orientado a esquemas
import Fastify from 'fastify';
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
const fastify = Fastify();
const createUserSchema = z.object({
username: z.string().min(3),
email: z.string().email(),
age: z.number().positive().int(),
});
type CreateUserRequest = z.infer;
fastify.post('/users', {
schema: { body: zodToJsonSchema(createUserSchema) },
}, async (request, reply) => {
const newUser = { id: Date.now(), ...request.body };
reply.code(201).send(newUser);
});
Fastify usa esquemas para validação e otimização de desempenho, transformando segurança de tipos em eficiência de tempo de execução.
NestJS: Declarativo via decoradores
import { Controller, Post, Body } from '@nestjs/common';
import { IsString, IsEmail, IsInt, Min, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(3)
username: string;
@IsEmail()
email: string;
@IsInt()
@Min(1)
age: number;
}
@Controller('users')
export class UsersController {
@Post()
create(@Body() userData: CreateUserDto) {
return { id: Date.now(), ...userData };
}
}
NestJS integra validação e tipagem através de decoradores de classe — sem necessidade de fiação manual.
Os benefícios: mais rápido, seguro e auto-documentado
O paradigma orientado por esquemas oferece melhorias mensuráveis em todos os aspectos:
| Aspecto | REST Clássico (Express + yup) | Orientado por Esquema (tRPC + Zod) |
|---|---|---|
| Velocidade de desenvolvimento | Lento e verboso: múltiplos esquemas, middleware e tratamento de erro manual. | Rápido e conciso: um esquema define todo o contrato; encanamento tratado pelo framework. |
| Segurança e confiabilidade | Frágil: casting de tipos manual e problemas de sincronização entre camadas. | Tipos seguros de ponta a ponta: esquema compartilhado entre servidor e cliente com validação em tempo de compilação. |
| Documentação | Manual e desatualizada: especificação OpenAPI separada que se desatualiza ao longo do tempo. | Automática e atual: ferramentas como trpc-openapi geram documentação ao vivo a partir do código. |
Conclusão
Construir APIs manualmente é uma relíquia do passado. A abordagem orientada por esquemas substitui o código repetitivo por contratos declarativos, permitindo que os frameworks lidem com o boilerplate.
Não se trata de escrever menos código — é sobre escrever código melhor. Um único esquema se torna sua camada de validação, sistema de tipos e documentação. Suas APIs são mais rápidas de construir, mais seguras de evoluir e mais fáceis de manter.
A mensagem é simples: pare de criar APIs REST do zero. Os frameworks de 2025 já sabem como fazer isso por você.