Saltar al contenido principal
Desarrollo Móvil

OpenAPI TypeScript: genera tipos, clientes y validación

Aprende cómo funciona la generación de OpenAPI TypeScript de principio a fin. Genera tipos, conecta clientes, valida en runtime y despliega de forma segura desde tu CI.

OpenAPI TypeScript: genera tipos, clientes y validación

Normalmente puedes detectar el momento en que un pipeline de API empieza a mentirle al equipo. Un esquema cambia, los tipos generados se actualizan sin errores, el PR sale en verde y, de repente, alguien en el frontend sigue leyendo la estructura de respuesta antigua porque el wrapper ocultó el error. Ese es el problema de OpenAPI TypeScript, no si un generador puede escupir interfaces.

La pregunta útil es más difícil. ¿Qué contrato quieres entre el esquema, el transporte y la validación, y qué partes deberían fallar rápido en tiempo de build en lugar de filtrarse al runtime? Una vez que planteas OpenAPI TypeScript como una decisión de pipeline, los trade-offs quedan mucho más claros y las herramientas dejan de pretender ser la solución completa.

Tabla de contenidos

Por qué los tipos generados no son lo mismo que un API seguro

Un compañero fusiona un PR que añade un campo de respuesta opcional. El archivo generado se actualiza sin problemas, el diff no llama la atención y todos siguen adelante. Luego el frontend sigue leyendo una estructura antigua a través de un wrapper escrito a mano que estaba “temporalmente” casteado con as any, y la producción empieza a comportarse como si el contrato nunca hubiera cambiado.

Esa es la trampa con los tipos generados. TypeScript solo puede proteger el code que consume los tipos generados, y solo si la capa de transporte no borra el contrato de nuevo. El lado de OpenAPI te da un schema, no una garantía de que cada caller lo respete. El discusión sobre la comprensión de las conexiones API es útil aquí porque desplaza la conversación desde una sola herramienta hacia cómo se conectan los sistemas.

Dónde se esconden los fallos

Los puntos de fallo más comunes son aburridos, no exóticos. Deriva del esquema ocurre cuando la especificación OpenAPI y el servicio desplegado dejan de coincidir. Cobertura parcial aparece cuando una especificación solo modela el caso feliz, mientras que la app depende de casos límite no documentados. Wrappers manuales suelen ser donde los tipos se debilitan, especialmente cuando alguien quiere “ir rápido” y usa any o un cast de respuesta laxo.

Regla práctica: si el wrapper puede mentir, el generador no puede salvarte.

También existe una brecha en runtime. Los tipos de TypeScript desaparecen tras la compilación, por lo que no pueden rechazar JSON malformado que llega por la red. La red no le importa lo que tu editor haya inferido, y por eso un cliente generado es solo una capa en un pipeline de API más seguro.

La pregunta operativa más amplia es la seguridad y la disciplina de contratos, no solo la comodidad del desarrollador. Si quieres una vista estructurada de cómo encajan los contratos de API en un ciclo de vida de app más amplio, esta guía interna sobre API security standards for app store compliance es un buen complemento.

La forma madura de pensar en openapi typescript es esta. Te da un puente estricto de esquema a tipos, lo cual es excelente, pero no valida solicitudes, no aplica la forma del payload en runtime ni detiene a un wrapper descuidado de socavar todo. El generador es el 20 por ciento fácil. El resto es diseño de pipeline, y ahí es donde los equipos ganan confianza o acumulan falsa seguridad.

Generar tipos TypeScript desde una especificación OpenAPI

Captura de pantalla de https://openapi-ts.dev

La configuración útil más ligera suele ser la que sobrevive al churn real del repo. Mantén la especificación OpenAPI en el mismo repositorio, genera un archivo de tipos comprometido y haz que el drift sea visible en CI en lugar de depender de que alguien recuerde un paso de actualización. Un comando como npx openapi-typescript ./openapi.yaml -o ./src/types/api.d.ts te da un archivo de salida determinista que los revisores pueden inspeccionar como cualquier otro cambio de código fuente.

Las flags que realmente importan

El -o el flag output importa porque hace explícito el artefacto generado. --immutable es útil cuando quieres que los tipos generados preserven la intención readonly en la salida, y --alphabetize mantiene los diffs estables cuando cambia el orden del esquema sin significado semántico. --enum importa cuando tu equipo prefiere enums en la superficie generada en lugar de unions.

La propia documentación del proyecto deja claro el alcance: es un generador de tipos, no un runtime de cliente ni una capa de peticiones, y esa limitación ayuda si buscas un setup ligero y centrado en tipos. Su repositorio también muestra el modelo de mantenimiento de la herramienta, lo que explica por qué el tooling open source puede aguantar en producción si la documentación y los releases se mantienen activos, como se analiza en la defensa del mantenimiento open source. Una lectura práctica sobre esa postura es el repositorio GitHub y la documentación CLI.

Integra la generación en package.json para que el comando esté junto al resto de los build scripts; ejecútalo cada vez que cambie el spec. En CI, regenera el archivo y falla si git diff muestra el drift. Eso convierte los cambios en el contrato en tareas de revisión visibles en lugar de riesgos silenciosos en tiempo de ejecución.

La parte del schema importa tanto como la línea de comandos. El proyecto recomienda compilerOptions.noUncheckedIndexedAccess para que additionalProperties convertirse en T | undefined, lo que obliga a un indexado más seguro en los call sites. También recomienda usar oneOf por sí solo en lugar de mezclarlo con composición extra, y mantener $defs en la raíz cuando la ubicación sea ambigua, ya que las definiciones mal ubicadas pueden desaparecer del output generado. Un detalle más te ahorrará tiempo después, openapi-typescript nunca producirá any, así que los detalles faltantes del esquema se detectan pronto en lugar de ocultarse tras tipos permisivos.

Mantén la spec explícita, o el generador te devolverá fielmente esa ambigüedad.

El workflow que perdura es sencillo. Pon la spec bajo control de versiones, regenera en cada build, haz commit del archivo generado y deja que el type checker avise antes de que alguien haga merge de un mismatch. Eso te da un límite de contrato estable para el resto del pipeline.

Elegir entre tipos puros, clientes completos o sin codegen

Patrón Tiempo de build Archivos de salida Peso del bundle Mejor opción
Tipos puros con un wrapper fino Rápido Pocos Bajo Equipos que buscan control y una superficie de runtime pequeña
Codegen de cliente completo Más lento Muchos Mayor Equipos que buscan una entrega rápida y operaciones autogeneradas
Sin request builders de codegen Rápido Ninguno o mínimo Bajo Apps de un solo codebase que prefieren lógica de transporte escrita a mano

La elección no es realmente “qué herramienta gana”. Es qué forma de pipeline encaja con tu repo, tu equipo y la cantidad de churn que ve API. En un benchmark de 2025 sobre una gran especificación OpenAPI de aproximadamente 75,000 líneas, 2 MB y unas 1,200 operaciones, openapi-typescript salida generada en aproximadamente 1,5 segundos de media, en comparación con aproximadamente 8,0 segundos para @hey-api/openapi-ts, 5,5 segundos para Orval, y 18,1 segundos para Kubb, mientras que también produce un único archivo de salida frente a 16 para hey-api, 2,719 para Orval, y 3,877 para Kubb (detalles del benchmark).

Tipos puros favorecen el control

Una configuración de solo tipos encaja bien con una capa de requests escrita a mano, ya que puedes mantener el runtime mínimo y la superficie de API predecible. Esto es clave en front ends sensibles al bundler y en apps donde un mismo equipo gestiona tanto la spec como el consumidor. Si necesitas un recordatorio de que la developer experience no es solo azúcar sintáctico, el ángulo de developer experience es más fácil de evaluar cuando tu cliente code es corto, obvio y revisable.

Clientes completos favorecen la velocidad de handoff

openapi-generator, hey-api, Orval, y Kubb todos intentan hacer más que generar tipos. Esto puede ser útil si quieres generar juntos métodos de request, modelos y la plomería, especialmente en handoffs grandes entre equipos de backend y frontend. El coste es evidente en el benchmark anterior: más archivos generados, más superficie de runtime y más margen para fricción en el build a medida que la spec crece.

Sin codegen se favorecen los refactors locales

Constructores de solicitudes tipados y fetch los wrappers funcionan bien cuando una sola base de código controla ambos extremos de la estructura y los cambios de API están estrechamente coordinados. La desventaja es la disciplina de mantenimiento. Cuantos más equipos y repositorios haya entre el productor y el consumidor, más probable es que una capa de solicitudes escrita a mano se desvíe, a menos que se apliquen pruebas de contrato de forma agresiva.

El punto de decisión central no es ideológico. Si tu presupuesto de bundle es ajustado, los tipos puros son atractivos. Si tu equipo quiere el máximo andamiaje y puede absorber la salida, los clientes completos reducen el tiempo de configuración. Si buscas un mínimo de piezas móviles y puedes mantener el contrato cerca, los constructores de solicitudes sin codegen pueden ser el intercambio interno adecuado.

Montar un cliente tipado ligero sobre Fetch o Axios

Un diagrama que ilustra un proceso de Typed Client Wrapper que utiliza definiciones de API de TypeScript generadas para solicitudes web.

Un wrapper fino es donde el generador se detiene y tu code de aplicación comienza. El wrapper debe exponer una función por operación, aceptar parámetros y objetos de consulta tipados, y reenviar la llamada a fetch o una instancia inyectada de axios instancia sin intentar ser ingenioso. En la mayoría de los entornos de producción, esa capa se mantiene 30–60 líneas porque los tipos generados ya llevan la mayor parte de la estructura.

Este es el modelo mental que se sostiene:

  • Los parámetros de ruta permanecen tipados para que /users/{id} no se puede llamar sin un id.
  • Los objetos de Query mantienen su tipado para que los filtros opcionales no se conviertan en un caos de strings.
  • Los cuerpos de respuesta mantienen su tipado así que al analizar code puede confiar en la forma estricta que espera.

Un wrapper así es intencionalmente aburrido. No debe inventar reintentos, transformaciones ni políticas de autenticación si esas responsabilidades pertenecen a otro lugar. Debe llevar la solicitud desde una operación tipada a la capa de transporte y luego devolver el resultado tipado hacia arriba.

Mantén el wrapper aburrido y con pocas dependencias, o cada cambio futuro de codegen se propagará por toda tu app.

El fallo común es parchear las discrepancias con as any cuando los tipos generados no coinciden con la firma del wrapper antiguo. Eso te da un build verde y una app frágil. Además, oculta justo la ruptura de contrato que querías que el generador revelara.

Para equipos que prefieren Axios, el patrón es el mismo, solo cambia la implementación del transporte. Para equipos que buscan un code más simple en el navegador, fetch suele ser suficiente. La parte importante es que la función de solicitud acepte el tipo de ruta generado y devuelva una respuesta tipada, no un objeto con forma laxa que se ajuste después.

Si aprovechas bien esta separación, openapi typescript te da una división del trabajo limpia. El esquema vive en la spec, el transporte en el wrapper, y la app ve operaciones tipadas en lugar de peticiones ad hoc code.

Añadir validación en runtime con zod, ajv o io-ts

Los tipos de TypeScript desaparecen en tiempo de ejecución, y a la red le da igual la confianza que te dé tu editor. Por eso el patrón seguro no es “generar tipos y esperar”, sino “generar tipos y luego validar en el límite donde los datos no confiables entran en la app”. El esquema generado sigue siendo la fuente de verdad, y las librerías de validación como zod, ajv, y io-ts handle the boundary checks that compile-time types can’t.

Valida donde entran los datos

En apps de React, el límite suele estar justo después de que se resuelva la petición y antes de que el payload entre en el estado. En servidores, antes de que el payload se escriba en una base de datos o se pase a una regla de negocio. La regla es simple: mantén la validación cerca del límite y no repartas comprobaciones manuales por el código de la feature code.

Una zod shape puede reflejar la forma de la respuesta generada sin reemplazarla:

import { z } from "zod";

const WeatherForecastSchema = z.object({
  date: z.string(),
  temperatureC: z.number(),
  summary: z.string().nullable(),
  temperatureF: z.number().optional(),
});

Ese ejemplo valida los campos que el schema marcó como opcionales y mantiene la validación en tiempo de ejecución alineada con lo que generó el generador. ajv es una opción sólida cuando necesitas validación de JSON Schema de alto rendimiento en el servidor, mientras que io-ts también encaja con equipos que ya trabajan en el fp-ts estilo de composición.

El gran error es validar demasiado tarde. Si el payload entra primero en tu app, el sistema de tipos ya se ha saltado y el bug tiene un lugar donde esconderse. Una breve guía sobre unit tests para JavaScript combina bien con esta mentalidad, porque tanto los unit tests como la validación en el límite funcionan mejor cuando detectan suposiciones incorrectas temprano.

La capa limpia es predecible. OpenAPI TypeScript genera el contrato, el validador comprueba el payload en tiempo de ejecución y tu app code solo ve datos que sobrevivieron a ambas etapas. Es un límite mucho mejor que confiar en un tipo estático para vigilar una respuesta no confiable.

Incluir generación, validación y tests de contrato en CI

Captura de pantalla de https://github.com

Un pipeline que perdura convierte el contrato en una puerta, no en una sugerencia. Regenera tipos, falla ante desviaciones, ejecuta tsc --noEmit, y probar la forma de API contra una herramienta de mock o contrato antes de hacer merge. Si fijas la versión del generador en package.json, dos ingenieros no pueden producir accidentalmente salidas diferentes a partir de la misma especificación.

Una estructura simple para GitHub Actions

Un flujo de trabajo práctico es así:

  1. Trae la spec del repo o de la fuente generada.
  2. Regenera los tipos.
  3. Haz fallar el job si git diff muestra cambios.
  4. Ejecuta tsc --noEmit.
  5. Ejecuta un contract test contra un mock server como Prism o un check basado en Spectral.

La diferencia clave entre contract tests y snapshot tests es el alcance. Los snapshots suelen avisarte de que el archivo cambió. Los contract tests te dicen si la estructura sigue comportándose como dice la spec.

Un mock server es especialmente útil cuando el trabajo de backend y frontend está separado por tiempos o por límites de equipo. Le da al consumidor code una superficie API predecible mientras valida el contrato real en lugar de un fixture hardcodeado. La guía de configuración de continuous integration es una referencia útil si tu equipo aún necesita una base de CI limpia y repetible.

Fijar la versión del generador evita uno de los peores fallos en los pipelines de codegen: el desfase invisible de la salida. Si un desarrollador actualiza el generador en local y otro no, el archivo generado puede convertirse en una fuente de ruido aleatorio en vez de señal. El CI debería hacerlo imposible.

El resultado es un pipeline donde los cambios de esquema, la generación de tipos, las comprobaciones del compilador y las pruebas de contrato se refuerzan mutuamente. Eso es lo que hace que el flujo de trabajo sea honesto.

Pipelines mantenibles, rendimiento y una checklist final

Lista de verificación con cuatro pasos clave para mantener un pipeline de OpenAPI TypeScript en proyectos de desarrollo de software.

Los pipelines que sobreviven son los que tienen una gobernanza aburrida. Versiona la especificación, revisa los cambios de esquema como code, fija la versión del generador y documenta cómo se aprueban los cambios rompedores. Si el proceso es vago, la gente lo evitará, y entonces los tipos generados se convierten en decoración en lugar de aplicación.

Algunas palancas de rendimiento sí importan

La generación incremental ayuda en monorepos donde la especificación cambia a menudo pero solo un paquete la consume. tsc --incremental puede reducir el trabajo repetido del compilador, y desactivar las banderas de salida que no necesitas en las compilaciones de producción mantiene la superficie generada más pequeña. En la práctica, la mayor ganancia sigue siendo social, no técnica, porque un pipeline predecible se ejecuta con más frecuencia que uno ingenioso.

La checklist de abajo es la que conviene tener a mano:

  • Fijación de versiones: Fija la openapi-typescript versión en package.json para que la salida no varíe entre máquinas.
  • Revisión del esquema: Treat spec changes as reviewable contract changes, not housekeeping.
  • Detección de desviaciones: Regenera en CI y falla si hay diferencias.
  • Validación en los límites: Parsea los payloads no confiables antes de que lleguen al estado de la app o a la persistencia.
  • Pruebas de contrato: Ejecuta una comprobación con mock que demuestre que el consumidor code sigue coincidiendo con el esquema.
  • Política de breaking changes: Documenta quién aprueba los cambios de forma y cómo se avisa a los clientes.

Un pipeline que incluye esos controles no solo genera tipos, sino que hace visible el contrato. Esa visibilidad es lo que evita que los equipos confíen en un archivo que solo parece seguro.

Si estás publicando Capacitor o apps Electron y quieres que tu pipeline de actualizaciones funcione con la misma disciplina, Capgo te ofrece una forma práctica de aplicar rápido correcciones de JavaScript, CSS, textos, configuración y assets sin esperar a la revisión de las tiendas de apps. Visita Capgo para ver cómo sus bundles firmados, la protección contra rollback y los controles de release encajan en un proceso de publicación que exige velocidad sin perder el control.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.