Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

OpenAPI com Node.js: Guia Prático

Atualizado em: 21 de agosto de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

OpenAPI com Node.js permite descrever uma API HTTP em um contrato legível por pessoas e ferramentas. O documento informa rotas, métodos, parâmetros, autenticação, schemas, respostas e exemplos. A partir dele, equipes podem gerar documentação, clientes, mocks, validações e testes de compatibilidade.

Uma especificação útil precisa acompanhar o comportamento real. Um arquivo bonito, mas desatualizado, aumenta erros e reduz confiança. Neste guia, você aprenderá a estruturar o contrato, reutilizar componentes, validar requisições e respostas e integrar a especificação ao pipeline. Para revisar conceitos básicos, leia o que é API e como criar uma API com Node.js.

O que é a especificação OpenAPI?

OpenAPI é um formato independente de linguagem para APIs HTTP. O documento pode ser escrito em YAML ou JSON. Ele não executa a aplicação, mas define o contrato que clientes e servidores devem seguir. Ferramentas utilizam essa descrição para criar interfaces interativas, SDKs e verificações automáticas.

O contrato deve representar decisões reais: quais campos são obrigatórios, quais formatos são aceitos, quais erros podem ocorrer e quais credenciais são necessárias. Evite descrições vagas como “objeto qualquer” ou respostas sem schema.

Estrutura inicial

openapi: 3.1.0
info:
  title: Orders API
  version: 1.0.0
  description: API para gerenciamento de pedidos
servers:
  - url: https://api.example.com
    description: Produção
paths:
  /orders/{orderId}:
    get:
      operationId: getOrder
      summary: Busca um pedido
      parameters:
        - $ref: '#/components/parameters/OrderId'
      responses:
        '200':
          description: Pedido encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          $ref: '#/components/responses/NotFound'
components: {}

Use operationId único e estável. Geradores de cliente frequentemente o transformam no nome do método. Alterá-lo pode quebrar integrações mesmo que a rota permaneça igual.

Definindo schemas reutilizáveis

components:
  schemas:
    Order:
      type: object
      additionalProperties: false
      required:
        - id
        - customerId
        - totalCents
        - status
        - createdAt
      properties:
        id:
          type: string
          format: uuid
        customerId:
          type: string
          format: uuid
        totalCents:
          type: integer
          minimum: 0
        status:
          type: string
          enum: [pending, paid, cancelled]
        createdAt:
          type: string
          format: date-time
    Error:
      type: object
      additionalProperties: false
      required: [code, requestId]
      properties:
        code:
          type: string
        message:
          type: string
        requestId:
          type: string

additionalProperties: false documenta que campos extras não pertencem ao contrato. Decida se o servidor realmente os rejeitará ou apenas os ignorará; documentação e implementação devem concordar.

Parâmetros

Parâmetros podem aparecer em path, query, header ou cookie. Parâmetros de path são sempre obrigatórios. Defina limites e formatos.

components:
  parameters:
    OrderId:
      name: orderId
      in: path
      required: true
      description: Identificador do pedido
      schema:
        type: string
        format: uuid
    PageSize:
      name: pageSize
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20

Não documente paginação sem explicar cursor, ordenação e estabilidade. Clientes precisam saber como obter a próxima página e quando um cursor expira.

Corpo de requisição

paths:
  /orders:
    post:
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderInput'
            examples:
              basic:
                value:
                  customerId: 4f583f15-4387-4f38-91ca-a657dc61980f
                  items:
                    - productId: SKU-123
                      quantity: 2
      responses:
        '201':
          description: Pedido criado
          headers:
            Location:
              schema:
                type: string
              description: URL do novo recurso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'

Exemplos ajudam consumidores e testes, mas não substituem schema. Mantenha exemplos válidos e sem dados reais ou segredos.

Documentando erros

Defina um formato consistente para erros. A resposta deve ter código estável, requestId e detalhes controlados. Não exponha stack trace ou mensagens do banco.

components:
  responses:
    NotFound:
      description: Recurso não encontrado
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: ORDER_NOT_FOUND
            message: Pedido não encontrado
            requestId: req_01JABC
    ValidationError:
      description: Dados inválidos
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Error'
              - type: object
                properties:
                  fields:
                    type: array
                    items:
                      type: object
                      required: [path, code]
                      properties:
                        path:
                          type: string
                        code:
                          type: string

Documente 400, 401, 403, 404, 409, 429 e 5xx quando realmente aplicáveis. Não liste todo status possível apenas para parecer completo.

Autenticação e autorização

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
security:
  - bearerAuth: []

O esquema informa como enviar a credencial, mas não descreve sozinho as permissões. Em cada operação, explique escopos, papéis ou regras de propriedade do recurso. Para tokens, consulte JWT seguro no Node.js.

Validação no servidor

O documento pode alimentar um middleware de validação. A ferramenta deve rejeitar parâmetros e bodies inválidos antes do caso de uso e, em testes ou homologação, validar também respostas.

import express from 'express';
import OpenApiValidator from 'express-openapi-validator';

const app = express();
app.use(express.json({ limit: '100kb' }));

app.use(OpenApiValidator.middleware({
  apiSpec: './openapi.yaml',
  validateRequests: true,
  validateResponses: process.env.NODE_ENV !== 'production',
  validateSecurity: false
}));

A opção de segurança deve ser integrada à autenticação real. Não habilite ou desabilite sem entender o comportamento da biblioteca. Validação de resposta em produção pode ter custo e transformar um erro de implementação em falha para o cliente; teste o impacto.

Tratando erros de validação

app.use((error, req, res, next) => {
  if (error.status && Array.isArray(error.errors)) {
    return res.status(error.status).json({
      code: 'INVALID_REQUEST',
      requestId: req.id,
      fields: error.errors.map(item => ({
        path: item.path,
        code: item.errorCode ?? 'INVALID'
      }))
    });
  }

  next(error);
});

Não envie o objeto original sem revisão. Bibliotecas podem incluir detalhes internos ou valores recebidos. Normalize a resposta no padrão público da API.

Design-first ou code-first?

No design-first, a equipe cria e revisa o contrato antes da implementação. Isso facilita colaboração com consumidores e geração antecipada de mocks. No code-first, decorators ou schemas do código geram a especificação, reduzindo duplicação.

As duas abordagens podem funcionar. O requisito é ter uma fonte principal clara, revisão de mudanças e verificação automática de divergência. Evite editar o YAML e schemas do código independentemente.

JSON Schema e OpenAPI 3.1

OpenAPI 3.1 está mais alinhado ao JSON Schema moderno. Ainda assim, ferramentas podem ter níveis diferentes de suporte. Valide a compatibilidade do ecossistema antes de usar recursos avançados.

Para schemas executáveis no código, consulte Zod no TypeScript. É possível gerar OpenAPI a partir de Zod ou gerar tipos a partir do contrato, mas revise a fidelidade da conversão.

Lint e governança

Um linter aplica regras como operationId obrigatório, descrições mínimas, formatos de erro e tags. Isso evita que cada equipe documente de uma forma.

npx @stoplight/spectral-cli lint openapi.yaml

Crie um conjunto pequeno de regras úteis. Regras excessivas geram exceções e reduzem adesão. Diferencie erro que bloqueia o merge de aviso para melhoria.

Detecção de breaking changes

Remover rota, campo, enum ou status pode quebrar clientes. Compare a especificação proposta com a versão publicada no pipeline. Mudanças aparentemente pequenas, como tornar um campo obrigatório, são incompatíveis.

  • adicionar campo opcional costuma ser compatível;
  • remover campo é incompatível;
  • reduzir enum pode quebrar clientes;
  • mudar tipo ou formato é incompatível;
  • adicionar requisito de autenticação é incompatível;
  • alterar semântica exige nova versão ou migração.

Geração de clientes

Geradores podem criar SDKs para TypeScript, Java, Kotlin e outras linguagens. Fixe a versão da ferramenta, revise o código e publique pacotes versionados. Não force consumidores a regenerar o cliente a cada deploy sem mudanças de contrato.

npx openapi-typescript openapi.yaml \
  --output src/generated/api-types.ts

Tipos gerados ajudam o compilador, mas respostas de rede ainda precisam de confiança no servidor ou validação no cliente quando o risco justificar.

Mocks

Um mock baseado em OpenAPI permite que frontend e integrações avancem antes do backend. Use exemplos realistas e inclua respostas de erro. Não trate o mock como prova de que a implementação final está correta.

Testes de contrato

Teste a implementação contra a especificação. Envie requisições válidas e inválidas, valide status, headers e schemas. Em integração, percorra operações críticas e confirme que exemplos continuam aceitos.

import test from 'node:test';
import assert from 'node:assert/strict';
import request from 'supertest';

test('rejeita pageSize acima do limite', async () => {
  const response = await request(app)
    .get('/orders?pageSize=1000')
    .set('Authorization', `Bearer ${token}`);

  assert.equal(response.status, 400);
  assert.equal(response.body.code, 'INVALID_REQUEST');
});

Veja também testes unitários com Jest.

Versionamento

Versione o contrato junto do código e publique uma cópia imutável para consumidores. A versão em info.version descreve o documento, mas a estratégia de versão da API precisa ser definida separadamente.

Prefira evoluções compatíveis. Uma nova versão principal custa manutenção, documentação e migração de clientes.

Segurança da documentação

  • não inclua tokens ou dados reais em exemplos;
  • separe servidores por ambiente;
  • não publique rotas internas sem necessidade;
  • proteja a interface interativa em ambientes privados;
  • limite “Try it out” quando houver operações sensíveis;
  • revise descrições para não expor infraestrutura;
  • mantenha schemas de autenticação corretos;
  • faça scan de segredos no repositório.

Observabilidade

Use operationId como dimensão estável em logs, métricas e traces. Isso agrupa chamadas pela operação documentada, evitando cardinalidade de URLs com IDs. Meça quantidade de falhas de validação e campos mais problemáticos para melhorar clientes e documentação.

Erros comuns

  • Gerar documentação uma vez: o contrato rapidamente fica desatualizado;
  • Usar schemas genéricos: ferramentas não conseguem validar nem gerar clientes;
  • Não documentar erros: consumidores dependem de mensagens instáveis;
  • Exemplos inválidos: testes e mocks ensinam uso incorreto;
  • Sem breaking-change check: alterações incompatíveis chegam silenciosamente;
  • Confiar apenas no TypeScript: dados HTTP continuam não confiáveis.

Checklist

  • operationId é único e estável;
  • parâmetros possuem limites e formatos;
  • schemas definem required e additionalProperties;
  • erros seguem um formato comum;
  • autenticação está documentada;
  • requests são validados;
  • lint e breaking changes rodam no CI;
  • exemplos e clientes são testados.

Referências oficiais

Conclusão

OpenAPI com Node.js transforma o comportamento HTTP em um contrato que pode ser revisado e automatizado. Schemas precisos, operationIds estáveis, erros documentados e exemplos válidos melhoram a experiência de quem produz e consome a API.

Integre a especificação ao código e ao pipeline: valide requisições, faça lint, detecte mudanças incompatíveis e execute testes de contrato. Dessa forma, a documentação deixa de ser um arquivo auxiliar e passa a ser uma parte verificável da arquitetura.

Os 10 Melhores Cursos de Programação de 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita