Saltar al contenido principal
Móvil Tutorial Guías

API en TypeScript: Cómo construir un API tipado listo para producción

Aprende a construir un API en TypeScript, desde el scaffolding hasta el despliegue, con DTOs tipados, validación, clientes y mejores prácticas de producción.

API en TypeScript: Cómo construir un API tipado listo para producción

Tu API en TypeScript probablemente parecía sólido el día del lanzamiento. Las rutas compilaban, el frontend importaba tipos compartidos y el editor daba esa sensación de éxito que suele significar “listo para enviar”.

Entonces el backend cambió un campo de respuesta, apareció un valor nullable donde nadie lo esperaba, o un cliente móvil siguió llamando a un payload con una estructura antigua. Ahí es donde la mayoría de los API en TypeScript el trabajo falla. No por la sintaxis. Por el drift.

Table of Contents

Por qué las APIs tipadas fallan tras el lanzamiento y cómo evitarlo

Una API tipada suele romperse durante un release normal. Un equipo renombra un campo de respuesta. Otro añade una rama nullable para una migración parcial. Un cliente antiguo sigue enviando el payload anterior porque las actualizaciones móviles van por detrás de la web. TypeScript sigue compilando en cada repo que actualizó sus tipos locales. El contrato en producción ya es falso.

Ese fallo tiene un nombre: contract drift.

Un diagrama que explica las tres razones principales por las que las API tipadas fallan en entornos de producción tras su lanzamiento inicial.

TypeScript hizo que trabajar con API fuera más agradable, pero también facilitó confiar demasiado en contratos débiles. Interfaces compartidas, genéricos de rutas y un tipo fetch ayudan durante el desarrollo. Pero no prueban que el JSON que viaja por la red siga coincidiendo con esos tipos tras el segundo o décimo release.

La regla que se mantiene en producción es simple.

Si un JSON sin validar llega directo a la lógica de la aplicación, tus tipos de TypeScript describen la intención, no la realidad.

La solución no es hacer gimnasia con los tipos, sino decidir dónde reside la verdad:

  • Valida en el boundary. Analiza el body, los params, los headers y hasta las respuestas de servicios externos antes de que el resto de code los procese.
  • Mapea los DTOs a modelos de dominio. Mantén los transport shapes separados de los objetos de negocio para que el churn de API no se filtre por todo el codebase.
  • Genera tipos a partir de un contrato. OpenAPI, JSON Schema o un framework schema-first dan a clientes y servidores una fuente de verdad compartida.
  • Trata los breaking changes como eventos públicos. Si el shape de un campo cambia, versiónalo deliberadamente y comunícalo como cualquier otro cambio en un contrato externo.

El mapeo de DTO es la pieza que los equipos se saltan más a menudo. Al principio parece redundante. Tras unos releases, se convierte en la capa que te evita propagar string | null y alias de campos heredados en cada servicio y pantalla del frontend. Un pequeño paso de traducción en el límite es más económico que un refactor masivo después.

Las APIs tipadas también fallan porque los contratos de error suelen ser algo secundario. Se presta atención a los payloads de éxito, pero los de error terminan siendo lo que sea que la excepción lanzada haya serializado ese día. Los clientes construyen su lógica de reintento, mensajes de usuario y monitoreo sobre shapes que nunca fueron diseñados. El resultado es el mismo problema con otra forma: drift.

El versionado merece la misma disciplina. Los equipos rara vez rompen clientes con un rewrite dramático; los rompen con una serie de cambios locales razonables que en conjunto generan incompatibilidad. Una estrategia clara de versionado de API para contratos en evolución hace que esos cambios sean visibles antes de que lleguen a los usuarios.

El objetivo no es tener TypeScript en todas partes. La meta es mantener el contrato íntegro tras el lanzamiento, cuando múltiples despliegues, clientes y datos reales de producción empiecen a desafiar los tipos perfectos que tenías el primer día.

Cómo estructurar tu proyecto API con TypeScript de la forma correcta

Un API tipado suele verse impecable el primer día. Seis meses después, una ruta acepta inputs sin validar, otra lee datos crudos process.env, y una tercera devuelve una estructura para la que ningún cliente fue programado. El scaffold rara vez se rompe de golpe; crea el espacio suficiente para que la deriva del contrato se filtre en el desarrollo de nuevas features.

Empieza con una estructura de proyecto que dificulte saltarse el contrato.

Un desarrollador escribiendo code en una laptop que muestra un error de TypeScript en la terminal del IDE.

Elige el framework que se adapte a tu equipo

Para un API en TypeScript, la primera decisión de framework no es tanto por la sintaxis, sino por dónde residirá la disciplina del contrato.

  • Express encaja con equipos que buscan una abstracción mínima y ya conocen el modelo de middleware. No estorba, lo cual es útil hasta que cada ruta empieza a inventar su propia validación, formato de error y convenciones de respuesta.
  • Fastify es una excelente opción por defecto para equipos de backend pequeños y medianos. Su sistema de plugins es limpio y acerca el trabajo de esquemas a la capa de rutas, ayudando a que el comportamiento en runtime esté alineado con los tipos.
  • Nest funciona muy bien en codebases grandes con muchos colaboradores, módulos compartidos y límites de propiedad claros. El coste es la verbosidad, y ese coste es real si el servicio es pequeño.

Suelo evitar comprar más framework del que el equipo realmente usará. Un servicio pequeño con Fastify, una librería de validación y tipos de contrato generados suele resistir mejor los refactors que un stack pesado con convenciones inconsistentes.

Usa una estructura de carpetas que proteja los límites

Los nombres de las carpetas importan menos que la presión de los imports. Si las rutas pueden acceder a los modelos de la base de datos, o los servicios devuelven entidades del ORM directamente al cliente, la estructura ya está propiciando el caos.

Un layout que aguante en producción suele separar las preocupaciones de transporte de las de la aplicación:

  • src/routes solo para la configuración de HTTP
  • src/schemas para esquemas de request y response
  • src/dto para tipos de transporte y mapeo de code
  • src/services para casos de uso y orquestación
  • src/domain para modelos de negocio que deban sobrevivir a cualquier endpoint
  • src/clients para integraciones downstream
  • src/errors para tipos de error compartidos y helpers de narrowing
  • src/config para el parsing de la configuración al arrancar

Esa src/dto capa no es trabajo de relleno. Le da a API un lugar donde absorber cambios externos sin filtrarlos a la lógica de dominio ni sacarlos de vuelta por endpoints no relacionados.

La configuración merece el mismo trato. Parsea las variables de entorno una vez al inicio, falla rápido ante valores inválidos y exporta un objeto de config tipado al resto de la app. Los equipos que siguen leyendo process.env dentro de los handlers, suele haber un comportamiento de ejecución con muchas ramificaciones que TypeScript no puede resolver. Esta guía sobre configuración de entorno es una buena referencia si necesitas estandarizar ese patrón.

Endurece el compilador antes de añadir features

Un API en producción debería hacer que escribir code inseguros sea molesto.

Algunos valores por defecto útiles son:

  • strict habilitado
  • useUnknownInCatchVariables habilitado
  • noUncheckedIndexedAccess se habilita si el equipo puede manejar la disciplina extra
  • Sin path aliases, a menos que Node, tests, bundling y tooling los resuelvan igual
  • Separados build, typecheck, y scripts de lint en CI

Uno débil tsconfig permite que el drift se acumule sin que nadie lo note. Uno estricto convierte los desajustes en tareas visibles antes de que lleguen a producción.

Las reglas de lint también ayudan, especialmente las que prohíben any, las floating promises y los exports accidentales de módulos de contrato público. Nada de esto reemplaza la validación en runtime, pero reduce los lugares donde pueden esconderse errores de contrato.

Otra elección de scaffolding es clave al inicio. Decide de dónde vendrá tu spec de OpenAPI y mantén esa decisión cerca de la capa de rutas. Algunos equipos la generan desde esquemas code-first. Otros generan server stubs y tipos desde la spec primero. Ambos enfoques funcionan. Lo que falla es tratar la spec como un artefacto secundario que nadie revisa tras el primer release.

Tras el scaffold inicial, ayuda comparar cómo se comportan los contratos tipados fuera de los servicios request-response simples. La Guía de Streamkap Flink TypeScript es útil para equipos que trabajan con streams o sistemas basados en eventos, donde el desajuste de contratos aparece en pipelines largos, no solo en handlers HTTP.

Diseño de DTOs y validación de inputs en el boundary

Un API tipado suele parecer correcto el primer día. Seis meses después, los bugs aparecen en el boundary. Un cliente móvil sigue enviando un campo antiguo. Un partner omite una propiedad que tu frontend asumía que siempre estaba presente. Un refactor expone una columna interna de un ORM en una respuesta pública. TypeScript hizo su trabajo dentro del codebase. El contrato se desajustó.

Por eso el diseño de DTOs es clave. No se trata de que los request bodies se vean ordenados. Se trata de mantener la integridad de los tipos públicos tras el primer release.

Los contratos públicos y los modelos internos no deben ser lo mismo

Un DTO describe lo que viaja por la red. Un modelo de dominio describe lo que la aplicación necesita para el trabajo real. Mezclar ambos conceptos ahorra unas líneas al principio, pero crea un acoplamiento costoso después.

Diagrama que ilustra el diseño de DTOs y los procesos de validación para mantener un boundary de sistema seguro y un contrato API.

Si tu ruta recibe esto:

type CreateOrderRequestDto = {
  customerId: string
  items: Array<{ sku: string; quantity: number }>
  note?: string | null
}

tu capa de servicio debería seguir aceptando algo más acotado y limpio, como un OrderDraft con strings normalizados, cantidades validadas y valores por defecto aplicados en un solo lugar.

El límite suele requerir estos pasos:

  1. Parsear el payload entrante
  2. Validar la estructura y las restricciones de cada campo
  3. Mapear el DTO a un objeto de dominio
  4. Ejecutar la lógica de negocio sobre el objeto de dominio
  5. Mapear el resultado a un DTO de respuesta
  6. Validar la respuesta saliente antes de enviarla

El paso seis se omite muchas veces. También es el paso que detecta campos privados, valores nullable que se filtraron en una respuesta estable y cambios accidentales en el esquema durante refactors.

Valida antes de que la lógica de negocio toque los datos

Los tipos en tiempo de compilación no validan el JSON de la red. Tampoco te protegen si otro servicio devuelve una estructura que aún cumple con unknown y rompe tus suposiciones en tiempo de ejecución.

Para que API funcione en TypeScript, Zod es una opción común porque parsea en runtime e infiere tipos para el resto de code. Valibot, io-ts y librerías similares también sirven. La librería importa menos que la regla: los datos no confiables se parsean antes de que cualquier otra cosa los use.

Un patrón que sobrevive a los refactors se ve así:

  • Schemas de entrada rechazan datos de peticiones malformados
  • Schemas de dependencias validan respuestas de APIs de terceros y servicios internos
  • Schemas de salida verifican la respuesta que tu API está por publicar

Esa capa intermedia es donde muchas APIs tipadas fallan tras el lanzamiento. Los equipos validan las peticiones, omiten la validación en las respuestas descendentes y luego se preguntan por qué el cambio de nombre de un campo de un proveedor se convierte en un incidente en producción.

Esta es la regla práctica que aplico: el JSON puro se detiene en la capa de rutas.

Mapear code no es un desperdicio. Es donde el drift se vuelve visible.

Los equipos suelen resistirse al mapeo de DTO porque parece repetitivo. Yo he visto lo contrario en producción. Una capa de mapeo ligera es donde los cambios de contrato se vuelven obvios, revisables y locales.

Por ejemplo:

  • el transporte permite note?: string | null
  • el modelo de dominio puede almacenar note: string con "" como el valor por defecto
  • el DTO de respuesta puede omitir note completamente cuando está vacío

Esas son tres verdades distintas para tres audiencias diferentes. Tratarlas como una única interfaz compartida oculta la diferencia hasta que un cliente falla.

Un webhook lo deja aún más claro porque los consumidores pueden mantener la estructura de tu payload durante años. Si tu equipo está lidiando con ese problema, este ejemplo de diseño de payload de webhook es un complemento útil.

Los tipos compartidos solo sirven si la fuente de verdad es explícita

Copiar interfaces del backend al frontend genera desajustes con el tiempo. Los paquetes compartidos ayudan, pero solo para tipos que sean intencionalmente públicos.

Una configuración más robusta para codebases grandes es la siguiente:

  • define esquemas de request y response públicos separados de los modelos de persistencia
  • genera OpenAPI desde esos esquemas públicos, o genera primero los tipos del servidor desde OpenAPI
  • mantén los tipos de contrato generados cerca de los handlers y clientes
  • mantén los tipos de dominio y los modelos ORM internos
  • versiona los DTOs públicos deliberadamente cuando la compatibilidad sea clave

Esa separación también es coherente con las guías de diseño de TypeScript del equipo SDK de Azure, que enfatizan superficies públicas estables y evitar exponer detalles de implementación interna en el contrato.

Un límite mantenible es aburrido a propósito

La buena versión es menos ingeniosa.

Antes, el frontend confía fetch().json() como si fuera la verdad, en que el backend devuelve objetos ORM directamente, y una interfaz compartida intenta representar cada capa. Después, cada límite parsea los datos, los DTOs se mantienen estrechos, los modelos de dominio permanecen internos, los tipos generados cubren el contrato público y el mapeo de code hace que los cambios sean explícitos.

Añade formalidad. También te permite revisar el drift en un solo lugar antes de que los clientes lo detecten por ti.

Generar y consumir un cliente API totalmente tipado

Un cliente tipado suele parecer terminado el día del lanzamiento. Tres meses después, un endpoint empieza a devolver un campo nullable, otro añade paginación por cursor y una app móvil se queda en una versión antigua del contrato. Los tipos de TypeScript siguen compilando. Los clientes se rompen.

Ese es el trabajo de la capa del cliente. Debe mantener la integridad del contrato publicado tras el primer release, no solo hacer que el autocomplete del editor se vea bien.

Elegir tu estrategia de cliente tipado

La estructura del cliente debe ajustarse a la complejidad real de API, no a la preferencia del equipo.

Enfoque Ideal para Compromisos
Wrapper de fetch manual Apps pequeñas, auth inusual, iteración rápida Rápido de iniciar. Fácil de fragmentar con el tiempo
Generación de code vía OpenAPI APIs REST directas con esquemas estables Base sólida. Requiere ayuda para auth custom, streaming o paginación inusual
Cliente tipado estilo SDK Plataformas multi-equipo, APIs públicas, integraciones largas Mayor costo de mantenimiento. Mejor experiencia si el API es un producto

Los clientes manuales sirven para superficies pequeñas

A custom fetch wrapper es una opción razonable si el API es interno, la superficie es pequeña o el comportamiento del transporte importa más que la generación de esquemas. Sigo usando este enfoque para herramientas de admin y servicios en etapas tempranas.

El modo de fallo es el drift. Un equipo añade una regla de reintento en el wrapper. Otro se la salta. Un tercero copia un tipo de respuesta al frontend y lo amplía a any tras el primer desajuste. Acabas con llamadas “tipadas” que ya no representan lo que devuelve el servidor.

Usa un cliente hecho a mano cuando se cumplan estas condiciones:

  • el API es pequeño e interno
  • el contrato cambia lo bastante a menudo como para que regenerar code sea ruido
  • el comportamiento de transporte personalizado domina el trabajo
  • estás dispuesto a mantener el parsing en runtime en el cliente, no solo anotaciones de TypeScript

Ese último punto es clave. response.json() devuelve datos unknown en runtime, aunque la firma de la función diga lo contrario.

La generación con OpenAPI es el estándar práctico

Para APIs REST estables, los tipos generados ofrecen la mejor relación entre mantenimiento y seguridad. Eliminan gran parte de la escritura duplicada de tipos y hacen visibles los cambios del contrato en los pull requests.

El patrón que sobrevive a los refactors es simple. Genera desde el contrato público, mantén la capa generada ligera y añade un pequeño wrapper donde tus consumidores necesiten mejor ergonomía. El Workflow de generación de OpenAPI con TypeScript se ajusta bien a ese modelo.

Una división útil sería esta:

  • el code generado gestiona las formas de request y response
  • un wrapper ligero de SDK gestiona la inyección de auth, retries y helpers de paginación
  • la validación en runtime sigue ocurriendo en el boundary del servidor y donde entre input no confiable
  • el mapeo de DTO se mantiene explícito para que los cambios en el modelo interno no afecten al contrato del cliente

Ese enfoque híbrido mantiene el code generado simple, lo cual es bueno. Un code simple es más fácil de regenerar, revisar y reemplazar.

Envuelve los clientes generados antes de que la aplicación code los use

Las funciones generadas suelen ser demasiado crudas para un uso general en el codebase. Exponen detalles de transporte que cada llamador debe reaprender.

Un wrapper ligero te permite centralizar la consistencia de tus políticas:

  • adjuntar headers por defecto y request IDs
  • normalizar la estructura de los errores
  • exponer la paginación como un iterador o método auxiliar
  • permitir overrides de auth por request en casos multi-tenant
  • preservar los tipos de request y response generados en vez de reescribirlos a mano

Por ejemplo, la aplicación code debería llamar a client.orders.listAll() o client.orders.list({ cursor }), no ensamblar query strings manualmente ni parsear metadatos de paginación en cada llamada.

Los clientes estilo SDK tienen sentido cuando el API es un producto

Las APIs públicas y servicios compartidos requieren más que funciones de endpoint generadas. Los consumidores esperan consistencia en el nombrado, errores predecibles y detalles de transporte ocultos tras métodos que sigan el dominio.

Una buena ergonomía del cliente suele verse así:

  • client.orders.list() devuelve una página tipada o un async iterator
  • client.files.stream() gestiona el streaming sin exponer la configuración de fetch en cada llamada
  • la auth se puede configurar globalmente y sobrescribir por request
  • los callers reciben objetos de error tipados y estables en lugar de payloads lanzados ad hoc

Eso aumenta el coste de mantenimiento. Además, evita que cada equipo consumidor reconstruya las mismas reglas de frontera de forma ligeramente distinta, que es como se propaga el contract drift.

Un cliente totalmente tipado no es la meta. La meta es un cliente cuyos tipos sigan coincidiendo con la realidad después de que API evolucione, porque la generación parte del contrato público, la validación en runtime protege el boundary y el mapeo de DTO evita que los cambios internos se filtren hacia afuera.

Error Handling, Testing y Observability que realmente ayudan

La mayoría de los ejemplos de API en TypeScript son demasiado tranquilos. Las peticiones funcionan, el JSON coincide con la interfaz y los errores se convierten en throw new Error("something went wrong"). En producción, las cosas nunca son tan amables.

El primer arreglo es mecánico. En TypeScript, los valores capturados deben tratarse como unknown, y luego se filtran antes de la lectura message, stack, o las propiedades de la response. La guía de expertos también recomienda usar custom error classes, preservando el fallo original con cause, validando en los límites, normalizando lanzamientos que no sean Error y adjuntando el contexto de la petición para observabilidad ("Guía de manejo de errores en TypeScript).

Una infografía con las cinco mejores prácticas para escribir code resilientes en producción usando TypeScript.

Reduce el tipo de error antes de usarlo

Los bloques catch inseguros siguen siendo comunes:

try {
  await client.orders.create(input)
} catch (error) {
  logger.error(error.message)
}

Eso es dar por sentado demasiado. error podría no ser un Error en absoluto.

Un patrón más seguro:

try {
  await client.orders.create(input)
} catch (error: unknown) {
  if (error instanceof Error) {
    logger.error({ message: error.message, stack: error.stack })
    throw new OrderSyncError("Order sync failed", { cause: error })
  }

  logger.error({ error })
  throw new OrderSyncError("Order sync failed", { cause: new Error("Non-Error thrown") })
}

Parece un poco más pesado. Sin embargo, resiste mucho mejor cuando hay fallos en SDKs de terceros, errores al parsear JSON o excepciones inesperadas.

Reintenta solo si el error es transitorio

La segunda gran mejora es la clasificación de errores. La guía para las operaciones de TypeScript SDK y API se basa en una regla clara: reintenta fallos transitorios como errores de red o respuestas HTTP 429 y 503, valida pronto, preserva el contexto del error y evita reintentos en fallos de reglas de negocio. Esa misma guía también recomienda Promise.all para un trabajo paralelo de tipo fail-fast y Promise.allSettled cuando un éxito parcial es aceptable (patrones de manejo de errores de SDK).

me gustan tres categorías:

  • Errores de validación significan que la petición era incorrecta antes de salir de tu proceso.
  • Errores transitorios pueden tener éxito al reintentar con backoff.
  • Errores permanentes reflejan reglas de negocio, permisos o recursos faltantes y deben mostrarse directamente.

Esa clasificación ofrece un mejor code que cualquier helper genérico de “retry on failure”.

Regla de campo: Los reintentos son por incertidumbre de transporte, no por desacuerdos de dominio.

La observabilidad debe explicar los fallos, no solo registrarlos

Los logs sin contexto no son observabilidad. Para API en TypeScript, adjunta un correlation ID, el nombre de la ruta, metadatos de la request y un formato de error normalizado cada vez que una request cruce un límite.

Una base útil:

  • IDs de correlación vinculan una request entrante con las llamadas downstream
  • Logs estructurados almacenan campos, no blobs de texto
  • Logs de frontera capturan fallos de parseo separados de las excepciones de negocio
  • Alerting se basa en la clase de error y la ruta, no solo en el status code volumen

Si tus aplicaciones móviles o clientes consumen estas APIs, la observabilidad también es clave. Una opción práctica en la capa de release es Capgo, que ofrece APIs tipadas para enviar y trackear Live Updates en entornos Capacitor y Electron. Es útil cuando un fix en el contrato del cliente requiere un rollout controlado y visibilidad por versión, en lugar de esperar a ciegas en la app store. Para equipos que buscan cerrar el feedback loop, esta guía sobre observabilidad de apps encaja perfectamente con el logging del lado del servidor.

Testea el contrato, no solo la implementación

Los unit tests por sí solos no detectarán el drift. Añade tests donde ocurra el drift.

  • Tests de validación de boundaries: Envía inputs malformados a los schemas y valida la forma del error.
  • Pruebas de contrato: Confirma que las respuestas HTTP reales coincidan con el contrato publicado.
  • Aserciones de errores tipadas: Verifica que los fallos transitorios y permanentes se normalicen correctamente.
  • Tests de integración del cliente: Asegura que los clientes generados o envueltos parseen respuestas reales.

Una suite de tests sólida para APIs tipadas no solo valida los paths de code. Demuestra que tu contrato sigue siendo veraz.

Lanza a Producción con Confianza y Control

La calidad de cada release viene de un loop repetible, no de heroísmos.

Un pipeline de API confiable en TypeScript suele tener varios esenciales: schema checks en CI, type checks en artefactos generados, revisión de contract diff antes del merge y un path de deployment que permita ralentizar o hacer rollback si la base de clientes no está lista.

El release loop que sí funciona

Me gusta mantener el checklist de producción lo suficientemente corto para que los equipos lo sigan:

  • Fallo en CI por contract drift: Si OpenAPI cambia, los tipos y clientes generados deben actualizarse en el mismo cambio.
  • Versionado de contratos compartidos: Los paquetes DTO públicos requieren disciplina de release, no refactorizaciones casuales.
  • Despliegue por canal o cohort: No expongas a todos los consumidores a un cambio de integración disruptivo de golpe.
  • Mantén el rollback simple: Revertir el contrato, el cliente o el web bundle debería ser una tarea rutinaria.

Para equipos que mueven su infraestructura y workflows de deployment a la vez, esta guía de migración a la nube para devs es una referencia útil, ya que la fiabilidad de API suele degradarse en transiciones de plataforma, no solo en cambios de code.

El control importa tanto como la corrección

El hábito final en producción es la visibilidad por versión. Debes saber qué build de cliente llama a qué contrato, qué releases se adoptaron con éxito y dónde se agrupan los fallos tras el rollout. Esto es vital para consumidores móviles o edge-distributed que no se actualizan de inmediato.

Si tu stack incluye Capacitor o Electron, el tooling de live update puede reducir el lag entre corregir un bug en un contrato y entregar el fix al usuario. Lo importante no son solo "updates más rápidos". Es tener despliegue por canales, protección contra rollback y observabilidad por versión so contract fixes stay controlled.

Las APIs tipadas se mantienen sanas cuando el schema, la validación en runtime, la generación de clientes y las operaciones de release se refuerzan entre sí. Si falta una capa, las demás terminan compensando mal.


Capgo permite a los equipos entregar fixes de web bundles de forma tipada en apps de Capacitor y Electron, controlar canales de rollout y monitorear la adopción y fallos por versión. Si tus fixes de contrato en API también deben llegar rápido a los clientes sin esperar la revisión de la store, visita Capgo.

Live Updates para apps de Capacitor

Si hay un bug en la capa web, publica el fix con 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 proceso de revisión normal.

Lo último de nuestro blog

Capgo te da los mejores insights para crear una app móvil realmente profesional.