Traducción de la página original en inglés. Si algo no cuadra, prevalece la versión en inglés.
Especificación OpenAPI de DaloyJS
DaloyJS emite un documento OpenAPI 3.1 limpio directamente desde tus definiciones de rutas, sin plugins ni decoradores aparte. La validación, los tipos y la especificación comparten una única fuente de verdad.
Una línea: monta automáticamente /docs, /openapi.json y /openapi.yaml
Al estilo de FastAPI. Pasa docs: "auto" (o docs: true) al constructor de App y DaloyJS registra por ti GET /openapi.json + GET /openapi.yaml (la especificación en vivo en ambos formatos) y GET /docs (una interfaz de referencia de API con Scalar).
docs: "auto" solo monta las rutas cuando la App no está en producción (las plantillas de create-daloy lo usan por defecto, así que una API desplegada no publica su esquema). También puedes dejarlo desactivado (el valor por defecto) y montarlas a mano con los helpers de más abajo. Personaliza las rutas, la interfaz y las etiquetas con la forma de objeto. Desde la 1.5.5, la forma de objeto se comporta como "auto" salvo que definas enabled, así que personalizar la interfaz nunca publica por accidente tu mapa de rutas en producción; define enabled: true (o docs: true) para una API pública que deba servir su documentación en producción:
Seguridad: una especificación publicada es un mapa completo de tu superficie de ataque: cada ruta, parámetro, esquema de autenticación y forma de error. Condocs: trueoenabled: trueen producción, DaloyJS registradocs.public_in_productiony sirve la especificación a cualquiera que pueda llegar a ella. Eso es lo correcto para una API pública. Para todo lo demás, mantén"auto"o pon la documentación detrás de autenticación (unbearerAuth()a nivel de aplicación sin unexcept()para/docsy/openapi.jsonlas cubre). Marca las rutas de administración, cron y depuración coninternal: true. Así quedan fuera del documento generado y responden404al tráfico de red, mientras queapp.inject()todavía puede llamarlas. Consulta Secure admin panels (en inglés).
Elige una interfaz: Scalar, Swagger UI o Redoc
Define ui como "scalar" (por defecto), "swagger" o "redoc". Las tres renderizan la misma especificación en vivo, se montan en las mismas rutas y traen la misma CSP estricta y los mismos recursos alojados en CDN, así que cambiar es cuestión de una palabra. Scalar y Swagger UI incluyen una consola de peticiones para desarrolladores con la que probar rutas protegidas. Redoc es una interfaz de referencia de solo lectura: muestra los requisitos de seguridad, pero no trae una consola Try it integrada.
Swagger UI conserva por defecto entre recargas las autorizaciones de su diálogo Authorize. Lo hace guardando el token pegado en el localStorage del navegador, igual que Scalar con persistAuth: true. Cualquier script que se ejecute en el origen de la documentación puede leerlo, y sobrevive al cierre de la pestaña. Pega solo tokens de prueba de corta duración y con los mínimos privilegios, nunca credenciales de producción o de administración, y sirve la documentación desde un origen distinto al de cualquier aplicación web propia. Pasa swagger: { persistAuthorization: false } para mantener los tokens solo en memoria. Scalar selecciona automáticamente el primer esquema de seguridad OpenAPI configurado, así que el formulario de autenticación está listo para que los desarrolladores peguen un token bearer o una API key. Si quieres otro valor por defecto en Scalar, defínelo explícitamente:
Si tu documentación necesita un punto de entrada visible para iniciar sesión, añade docs.auth. El mismo botón se renderiza en Scalar, Swagger UI y Redoc. Apúntalo a un formulario de inicio de sesión local, a una ruta de Better Auth, a la URL de inicio de sesión de Clerk o a una URL de autorización OIDC de Auth0, Okta, Microsoft Entra ID, Cognito, Keycloak u otro proveedor:
El objeto redoc se pasa tal cual a Redoc.init(specUrl, configuration, element). Como Redoc construye su índice de búsqueda en un Web Worker blob:, la ruta /docs montada automáticamente amplía la CSP de esa página con worker-src 'self' blob: solo para ui: "redoc". Scalar y Swagger UI mantienen la política más estricta. La opción scalar se ignora salvo que ui sea "scalar", y lo mismo ocurre con swagger y redoc.
El objeto scalar se pasa a la API HTML de Scalar como configuración JSON, mientras Daloy mantiene el openapiPath en vivo como fuente. Úsalo para temas, CSS personalizado, maquetación, valores de autenticación por defecto y visibilidad de clientes sin copiar el HTML de la documentación.
Avanzado: genera la especificación a mano
¿Necesitas el objeto de la especificación en bruto (para generación de código, pruebas de contrato o una ruta propia)? Llama directamente a generateOpenAPI(app, options):
Avanzado: sirve la documentación desde tu propia ruta
Una ruta de documentación hecha a mano es una ruta normal, así que el control de docs: "auto" no se le aplica. Decide tú si debe existir en producción y si necesita autenticación. Lo mismo vale para cualquier ruta /openapi.json que sirvas a mano con generateOpenAPI():
swaggerUiHtml, scalarHtml y redocHtml devuelven páginas HTML autocontenidas que cargan sus recursos desde jsDelivr con una CSP estricta que solo permite ese origen. Cuando montes la ruta a mano con redocHtml, pasa allowBlobWorkers: true a htmlResponse (o a docsContentSecurityPolicy) para que la CSP permita el worker de búsqueda blob: de Redoc:
Si quieres probar la experiencia de tu documentación con un contrato mucho mayor, consulta la demo REST falsa de gran tamaño (en inglés). Es una referencia mejor que un CRUD de juguete cuando necesitas validar la búsqueda, la agrupación y el rendimiento del renderizado.
Vuélcala a disco para la generación de código
Qué se emite
- Un
operationIdpor ruta; los duplicados lanzan un error en el registro. - Los parámetros de ruta
:idse normalizan a{id}. - Los cuerpos de los esquemas se convierten con
schema.toJSONSchema?.()cuando está disponible, o con una alternativa estructural. - Un
components.schemas.Problemreutilizable para los errores de la RFC 9457. tags,summary,descriptiony unadescriptionpor cada estado.- Las rutas marcadas con
internal: truese omiten salvo que pasesincludeInternal: true(por ejemplo, para un contrato solo interno destinado a tus propias herramientas). Nunca publiques ese documento.
Webhooks
OpenAPI 3.1 permite a un productor publicar webhooks de primer nivel, operaciones que se espera que implemente un consumidor. Pasa webhooks a generateOpenAPI y DaloyJS los emite en el mapa webhooks de primer nivel del documento.
El mapa webhooks solo describe la operación; no entrega ni protege nada. En las entregas reales, firma cada payload para que los receptores puedan verificar tanto el origen como la integridad, e incluye una marca de tiempo para que puedan rechazar las repeticiones. Un token bearer estático por sí solo no demuestra ninguna de las dos cosas. createWebhookSender() (en inglés) firma, añade la marca de tiempo, reintenta y pasa cada petición saliente por fetchGuard(). Los receptores verifican con verifyWebhookSignature(). Documenta las cabeceras de firma en la description del webhook.
Callbacks
Los callbacks describen peticiones fuera de banda que una operación puede desencadenar sobre el consumidor (por ejemplo, un endpoint de suscripción que más tarde hace POST a la URL que indicó quien llama). Añade un mapa callbacks directamente a una ruta o a un webhook.
Seguridad: una URL de callback indicada por quien llama es un punto de entrada para Server-Side Request Forgery. La validación del esquema no basta.z.url()por sí solo aceptahttp://169.254.169.254/(metadatos de la nube),http://localhost:6379/y URLsfile:/gopher:, e inclusoz.url({ protocol: /^https$/ })sigue aceptandohttps://169.254.169.254/o un nombre de host que resuelve a una dirección privada. Envía cada callback mediantesafeFetchdefetchGuard()(en inglés), que comprueba la dirección resuelta y cada salto de redirección. Mejor aún, entrégalos concreateWebhookSender()(en inglés), que además firma el payload. Plantéate verificar que la URL pertenece a quien la indica, por ejemplo con una petición de desafío, antes de guardarla.
Cada nombre de callback se asocia a una o varias claves de expresión en tiempo de ejecución (por ejemplo, "{$request.body#/callbackUrl}"), y cada una se asocia a una o varias operaciones indexadas por método HTTP. Los mapas y arrays vacíos se omiten: pasar un callback vacío nunca produce una especificación mal formada.
Uniones discriminadas
El discriminator de OpenAPI 3.1 es la forma canónica de describir uniones etiquetadas. DaloyJS ofrece dos helpers en @daloyjs/core/openapi (y en el paquete raíz):
discriminator(propertyName, mapping?): el constructor básico de la especificación. Úsalo cuando ya tienes un JSON Schema hecho a mano y quieres añadirle el campo de forma limpia.discriminatedUnion(propertyName, variants, opts?): un envoltorio compatible con Standard Schema que a la vez valida en tiempo de ejecución (despachando según el valor del discriminador) y expone.toJSONSchema()para que el generador de OpenAPI emita{ oneOf, discriminator }automáticamente.
En tiempo de ejecución, el envoltorio rechaza con un issue claro de Standard Schema los valores que no son objetos, los discriminadores ausentes o que no son cadenas y los valores de discriminador desconocidos (incluidos nombres heredados como __proto__, constructor y toString), y para todo lo demás delega en el validador de la variante correspondiente.
Última actualización: