@widergy/integration-docs
v1.3.0
Published
CLI para gestionar contratos OpenAPI de integración: import (Postman→OpenAPI con control) y export (OpenAPI→collection Postman). Reusable en productos Widergy (Ruby y Node).
Downloads
55
Keywords
Readme
@widergy/integration-docs
CLI para gestionar contratos OpenAPI de integración en los productos Widergy (Ruby y Node). Hace dos cosas:
import(one-time): genera un OpenAPI por integration desde la collection de Postman actual (nuestra doc), con un control (drift doc↔ejemplos reales + validación de ejemplos contra el schema). Se corre una vez por integration; después la collection vieja de Postman se descarta y la fuente de verdad pasa a ser el OpenAPI.export(ongoing): genera la(s) collection(s) de Postman desde los OpenAPI, preservando todos los examples y las descripciones. La collection es un artefacto read-only gitignored — se trabaja sobre el OpenAPI, nunca sobre la collection.
Por qué un CLI de node (y no una rake)
Corre en cualquier producto sin importar su lenguaje (UGO/Customer-Hub en Ruby, Workspace-API en NestJS, productos node-puro). Los artefactos son JSON/YAML, nativos de JS.
Uso en un repo
npm i -D @widergy/integration-docs- Crear
integration-docs.config.ymlen la raíz (ver*.config.example.yml). - Comandos:
# IMPORT (one-time): crear el OpenAPI de una integration desde la collection vieja de Postman
npx integration-docs import account_data # una
npx integration-docs import-all # todas las de importer.sources
# EXPORT (ongoing): generar la(s) collection(s) Postman desde los OpenAPI
npx integration-docs export # todas las collections del config
npx integration-docs export -c external # una puntual
# REPORT: regenerar el backlog de reconciliación desde los OpenAPI (sin re-importar)
npx integration-docs report # todas las collections
npx integration-docs report -c external # una puntualBacklog de reconciliación (_reconciliation.md)
import-all deja siempre un _reconciliation.md en la raíz del specsDir (junto a
_collection.md), trackeado en git. Es el worklist de contratos cuya doc no cierra con sus
propios ejemplos. Se va achicando a medida que arreglás los YAML: corré report para
regenerarlo (no necesita la collection vieja, lee los OpenAPI ya escritos). Buckets:
- 🔴 errores de schema (requerido faltante / type mismatch) — prioridad.
- 🟡 drift (keys en ejemplos no documentadas y viceversa).
- ⚪ sin schema (la doc no usa el formato de field-list parseable).
- ⚪ sin ejemplo de éxito para cruzar.
El field-list parser es plano: si la doc lista los campos de objetos anidados (items de un
array, sub-objetos), los valida como top-level y los marca faltantes. Eso aparece como error de
schema y es señal válida de reconciliación (el contrato debería modelar el anidamiento), pero no
es lo mismo que un typo real (dirección vs direccion). Leé el detalle, no solo el número.
El loop de reconciliación (nunca se edita el .md a mano)
1. Abrís _reconciliation.md → elegís un contrato 🔴
2. Editás SU .yml (el contrato) → arreglás la discrepancia
3. npx integration-docs report → relee TODOS los YAML y reescribe _reconciliation.md
4. Si quedó bien, el contrato sale del bucket y "limpios" sube
5. Commiteás el .yml + el _reconciliation.md actualizado juntosNo hay "marcar como resuelto": la tool deduce si está fixeado validando los ejemplos contra el
schema. El _reconciliation.md es el worklist; el contract-test (rspec/CI de cada repo) es el
gate — validan lo mismo, así que coinciden.
Qué editar según el bucket
| Bucket | Significa | Fix en el .yml |
|---|---|---|
| 🔴 missing required | el ejemplo no trae un campo que el schema marca requerido | el campo es opcional → sacalo de required; es typo → renombralo en properties+required; el ejemplo está mal → arreglá el ejemplo. Vos decidís qué lado es la verdad |
| 🔴 type mismatch | el tipo del ejemplo ≠ el del schema | corregí type (a veces el campo es un objeto/array anidado, no el escalar declarado) |
| 🟡 en doc SIN ejemplo | campo documentado que ningún ejemplo trae | agregá un ejemplo que lo incluya, o si es campo de request, sacalo del schema de response |
| 🟡 en ejemplo NO en doc | key real sin documentar | agregala a properties (suele ser el wrapper de un anidamiento) |
| ⚪ sin schema | la doc no usó el formato - **campo** _(tipo, req)_ | escribí properties a mano |
Recetas (escenarios reales del backlog de UGO)
A. Nombre equivocado / typo — la doc dice dirección, la realidad usa direccion:
# antes
required: [direccion] # ojo: con tilde en properties
properties:
dirección: { type: string } # ← el ejemplo trae `direccion`, esto no matchea
# después
properties:
direccion: { type: string } # renombrado para matchear el ejemplo realB. Campos anidados (la causa dominante de los 🔴) — la doc lista los campos dentro de un
array, pero la response los envuelve. Ej. g8_obtener (puntos de servicio): el ejemplo es
{ puntos_de_servicio: [ {punto_de_servicio_id, serie, ...} ] } pero el schema los puso
top-level. El fix modela el anidamiento (y de paso limpia el 🟡 puntos_de_servicio NO en doc):
# después
required: [puntos_de_servicio]
properties:
puntos_de_servicio:
type: array
items:
type: object
required: [punto_de_servicio_id, serie, capacidad, unidad_capacidad, estado]
properties:
punto_de_servicio_id: { type: string }
serie: { type: string }
capacidad: { type: number }
unidad_capacidad: { type: string }
estado: { type: string }
atributos_adicionales: { type: object }El validador solo chequea
requiredtop-level, así que al anidar, los campos internos dejan de dispararlo. Modelás bien el contrato y se va el falso positivo.
C. Type mismatch que en realidad es anidamiento — ej. j7_obtener: la doc declara
cuenta y deuda como string, pero el ejemplo trae objetos. No es cambiar a string: es que
son sub-objetos. Modelá cuenta: { type: object, properties: {...} }.
D. Doc describe el request, no la response — ej. d1_ingresar (login): la doc lista
email, password, uid, proveedor (el body que se envía) pero el ejemplo 200 es un token. Esos
campos NO van en el schema de la response → sacalos de properties/required y dejá el schema
acorde a lo que realmente devuelve.
E. ⚪ sin schema — la doc no usó el formato de viñetas, así que no hay properties. Escribilas
a mano tomando el ejemplo de éxito como referencia (key + type), marcando required lo que
siempre viene.
Estándar de carpetas
docs/integration/<collection>/<grupo1>/<grupoN>/<integration>.ymlEspeja la estructura de la collection de Postman. import escribe ahí (anidando por los grupos
del path, sin el item hoja, con los prefijos de orden limpios: "g. Cuentas" → "Cuentas").
export camina ese árbol recursivo y reconstruye las carpetas en la collection.
Cómo sabe qué OpenAPIs usar
Cada collection del config declara su specsDir (raíz). El CLI solo camina ahí (recursivo).
Para separar "estos sí / estos no" (contratos externos vs specs internos), cada grupo tiene su
propio dir raíz y su collection. Podés tener N collections con distinto nombre, dir y salida.
Flujo end-to-end
[import, 1 vez] collection Postman vieja ──import──▶ OpenAPI YAML (fuente, trackeado en git)
[de acá en más] se edita el OpenAPI ──export──▶ collection Postman (gitignored)
el contract-test (en cada repo) valida ejemplos vs schema en CIEl control (al importar)
import compara el contrato contra los ejemplos reales de respuesta y reporta (no falla):
- drift: keys que están en los ejemplos pero no en la doc, y viceversa
(cazó, p.ej., que la doc decía
direccióny la realidad usadireccion). - ejemplos que no cumplen el schema declarado.
Los ejemplos son respuestas reales documentadas, así que compararse contra ellos es el control de "la doc no está desactualizada". No depende del host ni de ningún archivo extra.
Qué NO se migra (importante)
El OpenAPI describe el contrato (qué expone el endpoint: request, response, examples, descripción). NO se lleva lo que es glue de runtime de Postman, porque OpenAPI no lo puede representar:
- Scripts (pre-request / post-response, p.ej.
pm.collectionVariables.set, token-chaining, "Environment setup"): es JS imperativo, fuera del alcance de OpenAPI. - Environments / credenciales: son secretos — no van a git ni al OpenAPI. Quedan en
Postman / Postman Vault. La collection generada usa los placeholders
{{baseUrl}},{{apikey}}, etc., así que tus environments existentes siguen funcionando contra ella. - Auth y variables a nivel collection: glue de testing, no contrato.
Si necesitás versionar una collection operativa con scripts/auth (las de testing por-utility), hacelo con su JSON nativo de Postman (p.ej. Postman Native Git), no con este tool: acá viven los contratos, no las collections operativas.
