Skip to content

@fc/swagger-nuxt-module ​

Módulo Nuxt especializado em Swagger / OpenAPI. Concentra-se em duas responsabilidades:

  • gerar specs (individual e opcionalmente agregada por namespace) a partir de blocos @swagger e tipos TypeScript, com validação de referências e diagnóstico detalhado;
  • fornecer o componente <SwaggerUi /> — um wrapper genérico em torno do swagger-ui como componente Vue 3 reativo, com estilos compatíveis com modo escuro.

Toda a UI de portal (landing page, cabeçalho, cards, alternador de tema, tokens visuais) é de responsabilidade da aplicação que consome o módulo (ex.: @fc/docs-api).

Instalação ​

bash
pnpm add @fc/swagger-nuxt-module

Configuração básica ​

ts
export default defineNuxtConfig({
  modules: ['@fc/swagger-nuxt-module'],
  swagger: {
    info: {
      title: 'Minha API',
      description: 'Descrição da API.',
      version: '1.0.0',
    },
    apis: ['./server/routes/**/*.ts'],
    routes: {
      json: '/_openapi.json',
      ui: '/_swagger',
    },
    uiDisponibilidade: 'dev-local',
    // Opcional e sem default: declare um scheme apenas se alguma operação for
    // referenciá-lo no `@swagger`. A proteção por chave de API não precisa
    // disto — é anotada em runtime a partir de `apiPublica.apiKey`.
    securitySchemes: {
      ApiKeyAuth: {
        type: 'apiKey',
        in: 'header',
        name: 'x-api-key',
      },
    },
    types: [
      {
        name: 'MinhaRespostaApi',
        src: './server/utils/tipos.ts',
      },
    ],
  },
})

Agregação por namespace ​

Na app hospedeira, adicione swagger.agregador. Cada documento agregado informa o id, o conteúdo exibido e as fontes de onde os paths serão lidos.

ts
export default defineNuxtConfig({
  modules: ['@fc/swagger-nuxt-module'],
  swagger: {
    info: { title: 'Portal', description: '...', version: '1.0.0' },
    apis: [],
    agregador: {
      documentos: [
        {
          id: 'rgps',
          titulo: 'RGPS',
          descricao: 'Endpoints previdenciários públicos.',
          fontes: [
            { app: '../prev-api', prefixosPath: ['/rgps/api/v1/', '/api/v1/'] },
            { app: '../rmi-api', prefixosPath: ['/rgps/api/v1/'] },
          ],
        },
      ],
    },
  },
})

O núcleo puro usado nessa agregação também é uma superfície pública para runtimes de servidor:

ts
import { agregarDocumentoSwagger } from '@fc/swagger-nuxt-module/agregador'

Ele aplica a mesma filtragem e validação do CLI, rejeitando colisões de path, schema e securityScheme, além de $ref interno quebrado. A ordem das fontes não altera o documento produzido nem o diagnóstico.

Metadados de um mesmo PathItem (parameters, $ref, servers, summary e description) só podem reaparecer com conteúdo estruturalmente idêntico. Conteúdo divergente falha com diagnóstico estável, em vez de depender da ordem das fontes.

Componente <SwaggerUi /> ​

O módulo registra globalmente o componente SwaggerUi, que inicializa programaticamente o swagger-ui no DOM. Ele recebe as props:

  • urlSpec — URL (relativa ou absoluta) da spec OpenAPI a renderizar;
  • tema — 'claro' | 'escuro'; aplicada ao wrapper para acompanhar o tema da aplicação;
  • layout — layout do Swagger UI; por padrão, StandaloneLayout;
  • opcoes — opções extras repassadas ao SwaggerUI(...);
  • plugins — plugins adicionais do Swagger UI.

Eventos emitidos:

  • pronto(instancia) — emitido quando o Swagger UI foi inicializado; a instância expõe getStore() e specActions para quem precisar interagir com o store do Swagger UI;
  • erro(erro) — emitido em caso de falha na inicialização.

Exemplo mínimo:

vue
<script setup lang="ts">
const urlSpec = '/_swagger/specs/principal.json'
const tema = 'escuro'
</script>

<template>
  <SwaggerUi :url-spec="urlSpec" :tema="tema" />
</template>

Modo escuro ​

O componente importa automaticamente swagger-ui-escuro.css, que aplica overrides quando a aplicação define o atributo data-fc-swagger-tema="escuro" em <html>. Recomenda-se repassar o mesmo estado via prop tema.

Extensões ​

O módulo não injeta plugins nem estado adicional. Para estender o Swagger UI (selectors, reducers, wrapComponents), passe um plugin próprio pela prop plugins e, se necessário, use o evento pronto para despachar ações no store via instancia.getStore().dispatch(...).

CLI ​

O módulo expõe dois binários:

  • generate-swagger-spec — lê a configuração swagger da app atual e grava apenas a spec individual em ./.swagger/principal.json (ou no caminho informado via --out). Uso típico em apps que expõem sua própria OpenAPI (ex.: prev-api, rmi-api, backoffice).
  • generate-swagger-spec-agregado — executa fluxo completo: gera a spec principal, gera uma spec por documento configurado em swagger.agregador e emite o manifest.json. Uso típico no app hospedeiro do portal (ex.: docs-api).
bash
generate-swagger-spec
generate-swagger-spec --out ./public/_swagger/specs/principal.json
generate-swagger-spec-agregado

Estrutura gerada pelo binário agregado (em public/_swagger/ por padrão):

  • specs/principal.json: spec agregada com todos os endpoints do portal;
  • specs/<id>.json: spec por documento configurado (ex.: specs/rgps.json);
  • manifest.json: manifesto dos documentos, com URLs relativas (./specs/<id>.json).

O diretório dos artefatos é sempre public/_swagger/; configurar outro valor em swagger.artefatos.diretorio é rejeitado antes de qualquer escrita. IDs de documento aceitam somente letras minúsculas, números e hífens, sem repetição. A publicação é atômica e o gerador só substitui uma saída identificada pelo marcador interno .fc-swagger. Ao migrar uma saída antiga ainda sem marcador, remova apenas public/_swagger/ uma vez e execute novamente o comando.

Runtime ​

Após executar spec:gen, a app expõe:

  • /_openapi.json: handler dinâmico com a spec individual e servers derivados da requisição atual (registrado pelo módulo);
  • /_swagger/specs/*.json, /_swagger/manifest.json: servidos estaticamente por public/_swagger/ via Nitro.

O contrato público canônico é /_openapi.json. O arquivo principal.json é somente a base imutável produzida no build: o runtime o lê e interpreta uma vez por processo, cria uma cópia independente para cada requisição e então aplica origem, autenticação e schemas do envelope de erro PDPJ. Essa cópia evita que dados derivados de um host ou de uma configuração contaminem a resposta seguinte. Rotas dos namespaces internos não entram no contrato gerado nem no documento servido.

Como a resposta depende da origem e da configuração em execução, /_openapi.json usa Cache-Control: no-store. Se a base não puder ser carregada, o consumidor recebe uma mensagem estável, sem caminho de arquivo ou detalhe do sistema; o diagnóstico completo fica restrito ao log do servidor.

A UI (landing, visualizador, rotas /_swagger e /_swagger/:documento) fica por conta da aplicação.

O runtime público recebe somente info, routes e uiDisponibilidade, usados pela UI automática. Globs, tipos, fontes do agregador, schemes e caminhos de geração não são serializados no payload do cliente. O handler OpenAPI usa diretamente o diretório padrão compartilhado com o gerador.

Quando uma operação já exige autenticação e seu path também exige chave de API, o transformador inclui ApiKeyAuth no mesmo requisito. Em OpenAPI isso significa que os dois controles são obrigatórios; objetos separados no array significariam alternativas e publicariam incorretamente “um ou outro”.

UI automática (/_swagger) ​

Quando uiAutomatica não é desativado, o módulo serve uma página HTML em routes.ui que carrega swagger-ui-dist do CDN unpkg.com. A dependência de CDN é intencional. Se os assets externos não carregarem (CDN indisponível, rede corporativa/proxy bloqueando, CSP restritiva) ou se o SwaggerUIBundle não inicializar dentro de 8 segundos, a página exibe um painel de erro nativo com:

  • explicação do problema e causas prováveis;
  • botão para recarregar a página;
  • link direto para routes.json, permitindo consumir a spec bruta por qualquer ferramenta externa.

A página também contém <noscript> com orientação equivalente para navegadores sem JavaScript.

Disponibilidade da UI automática ​

Use uiDisponibilidade para controlar quando a rota routes.ui deve responder:

  • sempre — comportamento legado; publica a UI em qualquer ambiente.
  • dev — publica apenas quando a aplicação está em modo de desenvolvimento.
  • dev-local — publica apenas em desenvolvimento local e host local (localhost, 127.0.0.1, ::1).

Fora do contexto permitido, a rota responde 404. Esse é o modo recomendado para apps que usam docs-api como portal público e querem manter /_swagger apenas como ferramenta local.

Diagnóstico de erros ​

O gerador falha com relatório consolidado quando encontra problemas como:

  • YAML/JSDoc inválido em blocos @swagger;
  • tipo raiz ausente ou schema TypeScript não serializável;
  • $ref interno quebrado;
  • securityScheme referenciado, mas não declarado;
  • conflito de path + method, metadado de PathItem, schema ou securityScheme durante agregação.

O relatório sempre aponta app, arquivo, tipo e trecho relevante para correção.