API REST com OpenAPI e SDK TypeScript
API REST pública com autenticação JWT, rate limiting por IP/tenant, documentação OpenAPI gerada do código e SDK TypeScript publicado no npm com tipos sincronizados.
- Hono
- TypeScript
- Zod
- Postgres
- OpenAPI
- Bun

Construí essa API para servir de backend público do meu portfólio: o site consome ela para listar projetos, posts, e enviar formulários. A ideia foi tratar a API como produto: documentação viva, SDKs versionados, e rate limiting justo.
Por que Hono
Hono roda em Bun, Vercel Edge, Cloudflare Workers, Deno, Node — o mesmo código. Para uma API pública, isso é enorme: posso mover de host sem reescrever nada. Performance também é o ponto: roteador baseado em radix tree, latência sub-ms no warm path.
1import { Hono } from 'hono'2import { zValidator } from '@hono/zod-validator'3import { z } from 'zod'45const app = new Hono()67const CreateProjectSchema = z.object({8 title: z.string().min(3).max(120),9 summary: z.string().min(10).max(280),10 tech: z.array(z.string()).min(1).max(20),11 liveUrl: z.string().url().optional(),12 repoUrl: z.string().url().optional(),13})1415app.post('/projects', zValidator('json', CreateProjectSchema), async (c) => {16 const data = c.req.valid('json')1718 // A partir daqui, data é CreateProject tipado.19 // Sem cast, sem unknown, sem narrow manual.20 const project = await db.projects.create({ data })2122 return c.json({ project }, 201)23})
OpenAPI gerado do código
Em vez de manter um openapi.yaml à mão, eu gero do código no build. Cada rota exporta seu schema Zod, e o @hono/zod-openapi monta o spec. Resultado: a documentação em /docs está sempre sincronizada com o que o servidor realmente aceita.
1import { OpenAPIHono } from '@hono/zod-openapi'23const app = new OpenAPIHono()45app.openapi(6 {7 method: 'post',8 path: '/projects',9 request: {10 body: { content: { 'application/json': { schema: CreateProjectSchema } } },11 },12 responses: {13 201: {14 description: 'Project created',15 content: { 'application/json': { schema: ProjectResponseSchema } },16 },17 400: { description: 'Validation error' },18 429: { description: 'Rate limit exceeded' },19 },20 },21 async (c) => {22 const data = c.req.valid('json')23 // ...24 }25)2627// Gera /doc e /openapi.json automaticamente28app.doc('/openapi.json', { openapi: '3.1.0', info: { title: 'Kayro API', version: '1.0.0' } })

Imagem de capa ilustrativa. Substitua no admin em Mídia.
O SDK npm é gerado do mesmo openapi.json via openapi-typescript. O consumidor importa o cliente tipado e o autocomplete do editor mostra os campos, retornos e erros de cada endpoint. Zero código de cola, zero chance de drift entre spec e implementação.