Pruebas de contrato para APIs: evitar cambios incompatibles en equipos ágiles
Las pruebas de contrato para APIs te ayudan a detectar cambios incompatibles antes de las publicaciones web y móviles. Pasos prácticos, errores a evitar y una lista de verificación rápida para enviar cambios.

Por qué siguen colándose cambios incompatibles en los lanzamientos
La mayoría de los equipos acaba teniendo una sola API que atiende a muchos clientes: una app web, una app iOS, una app Android y a veces herramientas internas. Aunque todos acuerden los “mismos” endpoints, cada cliente usa la API de formas ligeramente distintas. Una pantalla puede esperar que un campo exista siempre, mientras que otra solo lo usa cuando se aplica un filtro.
El problema real aparece cuando estas piezas se liberan en horarios distintos. Los cambios en el backend pueden ponerse en producción varias veces al día, la web despliega rápido y las versiones móviles avanzan más despacio por revisiones y despliegues escalonados. Ese desfase crea roturas sorpresivas: la API se actualiza para el cliente más reciente, pero la build móvil de ayer sigue en uso y ahora recibe respuestas que no puede manejar.
Cuando esto ocurre, los síntomas rara vez son sutiles:
- Una pantalla que de repente aparece vacía porque un campo fue renombrado o movido
- Bloqueos causados por nulls inesperados o objetos ausentes
- Tickets de soporte “Algo está roto” con pasos difíciles de reproducir
- Un pico en los logs de error justo después de un deploy del backend
- Releases de hotfix que añaden código defensivo en lugar de arreglar la causa raíz
Las pruebas manuales y QA suelen pasar por alto estos problemas porque los casos riesgosos no están en la ruta feliz. Un tester puede verificar que “Crear pedido” funciona, pero no probar una versión antigua de la app, un perfil parcialmente completado, un rol de usuario raro o una respuesta con una lista vacía. Añade caché, feature flags y despliegues gradual es, y tienes combinaciones que un plan de pruebas no cubre.
Un ejemplo típico: el backend reemplaza status: "approved" por status: { code: "approved" } para soportar localización. La web se actualiza el mismo día y funciona. Pero la release actual de iOS aún espera una cadena, no puede parsear la respuesta y los usuarios ven una página en blanco después de iniciar sesión.
Por eso existen las pruebas de contrato para APIs: no para reemplazar QA, sino para detectar estos cambios “funciona con mi cliente más reciente” antes de que lleguen a producción.
Qué es (y qué no es) la prueba de contrato
La prueba de contrato es una forma para que un consumidor de la API (una app web, una app móvil u otro servicio) y un proveedor de la API (tu backend) se pongan de acuerdo sobre cómo van a comunicarse. Ese acuerdo es el contrato. Una prueba de contrato comprueba una cosa simple: ¿sigue el proveedor comportándose como el consumidor depende, incluso después de cambios?
En la práctica, las pruebas de contrato para APIs se sitúan entre los tests unitarios y las pruebas end-to-end. Los tests unitarios son rápidos y locales, pero pueden pasar por alto desajustes entre equipos porque prueban código interno, no el límite compartido. Las pruebas end-to-end ejercitan flujos reales a través de muchos sistemas, pero son más lentas, difíciles de mantener y a menudo fallan por razones no relacionadas con un cambio de API (datos de prueba, timing de UI, entornos inestables).
Un contrato no es un documento enorme. Es una descripción enfocada de las peticiones que un consumidor enviará y las respuestas que debe recibir. Un buen contrato suele cubrir:
- Endpoints y métodos (por ejemplo, POST /orders)
- Campos requeridos y opcionales, incluidos tipos y reglas básicas
- Códigos de estado y forma de respuesta de error (cómo luce un 400 vs 404)
- Encabezados y expectativas de autenticación (token presente, content type)
- Defaults importantes y reglas de compatibilidad (qué pasa si falta un campo)
Aquí hay un ejemplo simple del tipo de rotura que una prueba de contrato detecta temprano: el backend renombra total_price a totalPrice. Los tests unitarios aún pueden pasar. Las pruebas end-to-end podrían no cubrir esa pantalla o fallar más tarde de forma confusa. Una prueba de contrato falla de inmediato y señala el desajuste exacto.
Conviene aclarar lo que la prueba de contrato no hace. No reemplaza pruebas de rendimiento, seguridad o pruebas completas de usuario. Tampoco detectará todos los bugs lógicos. Lo que sí hace es reducir el riesgo más común en equipos rápidos: un cambio “pequeño” en la API que rompe silenciosamente a un cliente.
Si tu backend se genera o cambia con frecuencia (por ejemplo, al regenerar APIs en una plataforma como AppMaster), las pruebas de contrato son una red de seguridad práctica porque verifican que las expectativas del cliente sigan válidas tras cada cambio.
Elige un enfoque de contrato para equipos web y móvil
Cuando web y móvil publican a menudo, la parte difícil no es “probar la API”. Es ponerse de acuerdo sobre qué no debe cambiar para cada cliente. Ahí es donde ayudan las pruebas de contrato, pero aún necesitas decidir quién posee el contrato.
Opción 1: Contratos impulsados por el consumidor (CDC)
Con los contratos impulsados por el consumidor, cada cliente (app web, iOS, Android, integración de un partner) define lo que necesita de la API. El proveedor entonces demuestra que puede satisfacer esas expectativas.
Esto funciona bien cuando los clientes se mueven de forma independiente, porque el contrato refleja el uso real, no lo que el equipo del backend cree que se usa. También encaja con la realidad multi-cliente: iOS puede depender de un campo que la web no usa, y la web puede preocuparse por ordenado o paginación que móvil ignora.
Un ejemplo simple: la app móvil depende de que price_cents sea un entero. La web solo muestra el precio formateado, por lo que nunca notaría si el backend lo cambiara a string. Un CDC desde móvil captaría ese cambio antes del release.
Opción 2: Esquemas controlados por el proveedor
Con un esquema controlado por el proveedor, el equipo del backend publica un contrato único (a menudo un esquema o spec) y lo hace cumplir. Los consumidores prueban contra esa única fuente de verdad.
Esto encaja cuando la API es pública o compartida entre muchos consumidores que no controlas, o cuando necesitas consistencia estricta entre equipos. También es más sencillo para empezar: un contrato, un lugar para revisar cambios, un camino de aprobación.
Una guía rápida para elegir:
- Elige CDCs cuando los clientes publiquen con frecuencia y usen porciones diferentes de la API.
- Elige esquemas del proveedor cuando necesites un contrato “oficial” y estable para todos.
- Usa un híbrido cuando puedas: un esquema del proveedor como base y CDCs para los endpoints de alto riesgo.
Si construyes con una plataforma como AppMaster, la idea es la misma: trata a las apps web y nativas como consumidores separados. Aunque compartan backend, rara vez dependen exactamente de los mismos campos y reglas.
Qué incluir en un contrato de API (para que detecte roturas reales)
Un contrato de API solo ayuda si refleja de verdad lo que tus clientes web y móviles necesitan. Una spec bonita que nadie usa no detectará el cambio que rompe producción.
Empieza por el uso real, no por suposiciones. Toma las llamadas de cliente más comunes (desde el código de la app, los logs del gateway o una lista corta proporcionada por los equipos) y conviértelas en casos de contrato: la ruta exacta, el método, encabezados, parámetros de query y la forma típica del body. Esto mantiene el contrato pequeño, relevante y difícil de discutir.
Incluye tanto respuestas de éxito como de fallo. Los equipos a menudo prueban el camino feliz y olvidan que los clientes dependen de los errores también: el código de estado, la forma del error e incluso códigos/mensajes de error estables. Si una app móvil muestra el texto “email ya usado”, un contrato debería fijar esa respuesta 409 para que no se convierta en un 400 con otro cuerpo.
Presta especial atención a las áreas que más se rompen:
- Campos opcionales vs requeridos: eliminar un campo suele ser más seguro que convertir un opcional en requerido.
- Nulls: algunos clientes tratan
nulldistinto a “ausente”. Decide qué permites y mantén consistencia. - Enums: añadir un valor nuevo puede romper clientes antiguos que asumen una lista cerrada.
- Paginación: acuerda parámetros y campos de respuesta (como
cursoronextPageToken) y mantenlos estables. - Formatos de fecha y números: explícitalos (ISO strings, céntimos en enteros, etc.).
Cómo representar el contrato
Elige un formato que los equipos lean y que las herramientas puedan validar. Opciones comunes: JSON Schema, contratos basados en ejemplos o modelos tipados generados desde un spec OpenAPI. En la práctica, ejemplos más check de esquema funcionan bien: los ejemplos muestran payloads reales, y las reglas de esquema detectan “campo renombrado” o “tipo cambiado”.
Una regla simple: si un cambio obligaría a actualizar un cliente, debería fallar una prueba de contrato. Esa mentalidad mantiene los contratos centrados en roturas reales, no en perfección teórica.
Paso a paso: añade pruebas de contrato a tu pipeline CI
El objetivo de las pruebas de contrato para APIs es simple: cuando alguien cambia la API, tu CI debe decirte si algún cliente web o móvil se romperá antes de que el cambio se publique.
1) Empieza capturando de qué dependen los clientes
Elige un endpoint y anota las expectativas importantes en uso real: campos requeridos, tipos, valores permitidos, códigos de estado y respuestas de error comunes. No intentes describir toda la API de golpe. Para móviles, incluye también las expectativas de versiones antiguas de la app, ya que los usuarios no actualizan al instante.
Una forma práctica es tomar algunas peticiones reales que los clientes hacen hoy (desde logs o fixtures de prueba) y convertirlas en ejemplos repetibles.
2) Coloca los contratos donde los equipos los mantendrán
Los contratos fallan cuando viven en una carpeta olvidada. Mantenlos cerca del código que cambia:
- Si un equipo controla ambos lados, guarda los contratos en el repo del API.
- Si equipos distintos controlan web, móvil y API, usa un repo compartido administrado por los equipos, no por una sola persona.
- Trata las actualizaciones de contrato como código: revisadas, versionadas y discutidas.
3) Añade comprobaciones en ambos lados en CI
Quieres dos señales:
- Verificación del proveedor en cada build de la API: “¿El API sigue satisfaciendo todos los contratos conocidos?”
- Comprobaciones del consumidor en cada build del cliente: “¿Este cliente sigue siendo compatible con el contrato publicado más reciente?”
Esto detecta problemas en ambas direcciones. Si la API cambia un campo de respuesta, falla la pipeline del API. Si un cliente empieza a esperar un campo nuevo, falla la pipeline del cliente hasta que la API lo soporte.
4) Decide la regla de fallo y aplícala
Sé explícito sobre qué bloquea un merge o release. Una regla común: cualquier cambio que rompa un contrato falla el CI y bloquea el merge a main. Si necesitas excepciones, exige una decisión por escrito (por ejemplo, una fecha de lanzamiento coordinada).
Ejemplo concreto: el backend renombra totalPrice a total_amount. La verificación del proveedor falla inmediatamente, así que el equipo del backend añade el campo nuevo manteniendo el antiguo durante un periodo de transición, y web y móvil siguen publicando con seguridad.
Versionado y compatibilidad hacia atrás sin frenar a los equipos
Los equipos rápidos suelen romper APIs al cambiar lo que clientes existentes ya esperan. Un “cambio incompatible” es cualquier cosa que haga que una petición previamente funcional falle, o que cambie la respuesta de forma que el cliente no pueda manejar.
Aquí hay cambios comunes que rompen (incluso si el endpoint sigue existiendo):
- Eliminar un campo de respuesta que los clientes leen
- Cambiar el tipo de un campo (por ejemplo,
"total": "12"a"total": 12) - Convertir un campo opcional en requerido (o añadir un nuevo campo requerido en la petición)
- Cambiar reglas de autenticación (un endpoint público ahora necesita token)
- Cambiar códigos de estado o forma de error que el cliente parsea (200 a 204, o un nuevo formato de error)
La mayoría de los equipos puede evitar los bumps de versión eligiendo alternativas más seguras. Si necesitas más datos, añade un campo nuevo en lugar de renombrar uno. Si necesitas un endpoint mejor, añade una ruta nueva y mantén la antigua. Si necesitas endurecer validaciones, acepta ambas entradas por un tiempo y luego aplica gradualmente las nuevas reglas. Las pruebas de contrato ayudan porque te obligan a demostrar que los consumidores existentes siguen recibiendo lo esperado.
La deprecación es la parte que permite mantener la velocidad sin perjudicar a los usuarios. Los clientes web pueden actualizar a diario, pero las apps móviles pueden quedarse atrás semanas por colas de revisión y adopción lenta. Planifica la deprecación según el comportamiento real de los clientes, no por esperanza.
Una política práctica de deprecación se ve así:
- Anuncia el cambio con antelación (notas de release, canal interno, ticket)
- Mantén el comportamiento antiguo hasta que el uso caiga por debajo de un umbral acordado
- Devuelve advertencias en headers/logs cuando se use la ruta desaprobada
- Fija una fecha de eliminación solo después de confirmar que la mayoría de clientes han actualizado
- Elimina el comportamiento antiguo solo cuando las pruebas de contrato muestren que ningún consumidor activo lo necesita
Usa versionado explícito solo cuando no puedas mantener compatibilidad hacia atrás (por ejemplo, un cambio fundamental en la forma del recurso o en el modelo de seguridad). Versionar añade coste a largo plazo: ahora mantienes dos comportamientos, dos conjuntos de docs y más casos borde. Mantén las versiones raras y deliberadas, y usa contratos para asegurar que ambas versiones sigan honestas hasta que la antigua sea segura de eliminar.
Errores comunes en las pruebas de contrato (y cómo evitarlos)
Las pruebas de contrato funcionan mejor cuando verifican expectativas reales, no una versión de juguete de tu sistema. La mayoría de fallos proviene de patrones previsibles que hacen que los equipos se sientan seguros mientras los bugs se cuelan a producción.
Error 1: Tratar los contratos como “mocks elegantes”
El sobre-mockeo es la trampa clásica: la prueba de contrato pasa porque el comportamiento del proveedor fue simulado para ajustarse al contrato, no porque el servicio real pueda hacerlo. Al desplegar, la primera llamada real falla.
Una regla más segura: los contratos deben verificarse contra el proveedor en ejecución (o un artefacto de build que se comporte igual), con serialización real, validación real y reglas de auth reales.
Estos son los fallos que aparecen con más frecuencia y la corrección que suele funcionar:
- Sobre-mockear el comportamiento del proveedor: verifica contratos contra una build real del proveedor, no contra un stub.
- Hacer los contratos demasiado estrictos: usa coincidencias flexibles para IDs, timestamps y arrays; evita afirmar cada campo si los clientes no dependen de ellos.
- Ignorar respuestas de error: prueba al menos los principales casos de error (401, 403, 404, 409, 422, 500) y la forma del body que el cliente parsea.
- Falta de ownership claro: asigna quién actualiza el contrato cuando cambian los requisitos; hazlo parte de la “definition of done” para cambios de API.
- Olvidar realidades móviles: prueba con redes más lentas y versiones de app antiguas en mente, no solo la última build en Wi‑Fi rápido.
Error 2: Contratos frágiles que bloquean cambios inofensivos
Si un contrato falla cada vez que añades un campo opcional o reordenas claves JSON, los desarrolladores aprenden a ignorar el build rojo. Eso anula el propósito.
Apunta a “estricto donde importa”. Sé estricto con campos requeridos, tipos, valores enum y reglas de validación. Sé flexible con campos extra, orden y valores que varían naturalmente.
Un ejemplo pequeño: tu backend cambia status de "active" | "paused" a "active" | "paused" | "trial". Si una app móvil trata valores desconocidos como un crash, esto es un cambio incompatible. El contrato debe detectarlo comprobando cómo el cliente maneja valores enum desconocidos, o exigiendo que el proveedor siga devolviendo solo los valores conocidos hasta que todos los clientes los soporten.
Los clientes móviles merecen atención extra porque viven más tiempo en el wild. Antes de declarar un cambio de API “seguro”, pregúntate:
- ¿Pueden las versiones antiguas de la app parsear aún la respuesta?
- ¿Qué pasa si la petición se reintenta tras un timeout?
- ¿Los datos cacheados colisionarán con el nuevo formato?
- ¿Tenemos una alternativa cuando falta un campo?
Si tus APIs se generan o se actualizan rápidamente (incluyendo con plataformas como AppMaster), los contratos son una guía práctica: te permiten moverte rápido demostrando que web y móvil seguirán funcionando tras cada cambio.
Lista rápida antes de enviar cambios en la API
Usa esto justo antes de mergear o lanzar un cambio en la API. Está diseñado para atrapar las pequeñas ediciones que causan los mayores incendios cuando web y móvil publican seguido. Si ya haces pruebas de contrato, esta lista te ayuda a centrarte en las roturas que los contratos deberían bloquear.
Las 5 preguntas que debes hacer cada vez
- ¿Añadimos, eliminamos o renombramos algún campo de respuesta que los clientes leen (incluyendo campos anidados)?
- ¿Cambió algún código de estado (200 vs 201, 400 vs 422, 404 vs 410) o cambió el formato del body de error?
- ¿Algún campo cambió entre requerido y opcional (incluyendo “puede ser null” vs “debe estar presente”)?
- ¿Cambió el orden, paginación o filtros por defecto (tamaño de página, orden, tokens de cursor, valores por defecto)?
- ¿Se ejecutaron las pruebas de contrato para el proveedor y todos los consumidores activos (web, iOS, Android y herramientas internas)?
Un ejemplo simple: tu API solía devolver totalCount, y un cliente lo usa para mostrar “24 resultados”. Lo quitas porque “la lista ya tiene items”. Nada falla en el backend, pero la UI empieza a mostrar vacío o “0 resultados” para algunos usuarios. Eso es una rotura real, aunque el endpoint devuelva 200.
Si respondiste “sí” a alguno
Haz estos pasos antes de publicar:
- Confirma si los clientes antiguos seguirán funcionando sin actualizar. Si no, añade una vía retrocompatible (mantén el campo viejo o soporta ambos formatos por un tiempo).
- Revisa el manejo de errores en los clientes. Muchas apps tratan formas de error desconocidas como “algo falló” y ocultan mensajes útiles.
- Ejecuta pruebas de contrato de consumidores para cada versión liberada del cliente que aún soportas, no solo la rama más reciente.
Si construyes herramientas internas rápido (por ejemplo, un panel admin o dashboard de soporte), asegúrate de incluir también a esos consumidores. En AppMaster, los equipos a menudo generan web y apps móviles a partir de los mismos modelos backend, lo que facilita olvidar que un pequeño cambio de esquema aún puede romper un cliente publicado si el contrato no se comprueba en CI.
Ejemplo: atrapar una rotura antes de que web y móvil publiquen
Imagina una configuración común: el equipo de API despliega varias veces al día, la web publica a diario y las apps móviles lo hacen semanalmente (por revisión de app stores y despliegues escalonados). Todos se mueven rápido, así que el riesgo real no es mala intención, sino pequeños cambios que parecen inofensivos.
Un ticket de soporte pide nombres más claros en la respuesta del perfil de usuario. El equipo de API renombra un campo en GET /users/{id} de phone a mobileNumber.
Ese renombre parece ordenado, pero es una rotura. La web podría renderizar un número de teléfono vacío en la página de perfil. Peor aún, la app móvil podría colapsar si trata phone como requerido, o fallar la validación al guardar el perfil.
Con pruebas de contrato, esto se detecta antes de que llegue a los usuarios. Así suele fallar, según cómo ejecutes las comprobaciones:
- Fallo en el build del proveedor (lado API): el job de CI del API verifica el proveedor contra contratos de consumidor guardados de web y móvil. Ve que los consumidores aún esperan
phone, pero el proveedor devuelvemobileNumber, así que la verificación falla y el deploy se bloquea. - Fallo en el build del consumidor (lado cliente): el equipo web actualiza su contrato para requerir
mobileNumberantes de que la API lo publique. Su prueba de contrato falla porque el proveedor aún no suministra ese campo.
En cualquiera de los dos casos, la falla es temprana, clara y específica: apunta al endpoint exacto y al campo que no coincide, en lugar de aparecer como “la página de perfil está rota” tras el release.
La solución suele ser simple: hacer el cambio aditivo, no destructivo. La API devuelve ambos campos durante un tiempo:
- Añadir
mobileNumber. - Mantener
phonecomo alias (mismo valor). - Marcar
phonecomo deprecated en las notas del contrato. - Actualizar web y móvil para leer
mobileNumber. - Eliminar
phonesolo cuando confirmes que todas las versiones soportadas han cambiado.
Un cronograma realista bajo presión de lanzamiento podría verse así:
- Lun 10:00: El equipo de API añade
mobileNumbery mantienephone. Las pruebas de proveedor pasan. - Lun 16:00: Web cambia a
mobileNumbery publica. - Jue: Móvil cambia a
mobileNumbery envía release. - Martes siguiente: La release móvil llega a la mayoría de usuarios.
- Sprint siguiente: El API elimina
phoney las pruebas de contrato confirman que ningún consumidor soportado aún lo necesita.
Este es el valor central: las pruebas de contrato convierten la “ruleta de cambios incompatibles” en una transición controlada y temporal.
Próximos pasos para equipos que se mueven rápido (incluida una opción sin código)
Si quieres que las pruebas de contrato realmente prevengan roturas (no solo añadan más comprobaciones), mantén el despliegue pequeño y deja claro quién es responsable. El objetivo es simple: detectar cambios incompatibles antes de que afecten a web y móvil.
Empieza con un plan de rollout ligero. Elige los 3 endpoints que más dolor causan cuando cambian —suele ser auth, perfil de usuario y un endpoint core de lista/búsqueda—. Asegura esos primero, y amplia una vez el equipo confíe en el flujo.
Un rollout práctico y manejable:
- Semana 1: pruebas de contrato para los 3 endpoints principales, ejecutadas en cada pull request
- Semana 2: añade los siguientes 5 endpoints con más uso móvil
- Semana 3: cubre respuestas de error y casos límite (estados vacíos, errores de validación)
- Semana 4: convierte “contrato en verde” en una puerta de release para cambios de backend
Luego, decide quién hace qué. Los equipos avanzan más rápido cuando está claro quién posee una falla y quién aprueba un cambio.
Mantén roles simples:
- Propietario del contrato: normalmente el equipo de backend, responsable de actualizar contratos cuando cambia el comportamiento
- Revisores consumidores: leads de web y móvil que confirman que los cambios son seguros para sus clientes
- Build sheriff: rota diaria o semanalmente, triagea fallos de pruebas de contrato en CI
- Propietario de release: decide bloquear un release si un contrato está roto
Mide un éxito que importe a todos. Para muchos equipos, la mejor señal es menos hotfixes tras releases y menos “regresiones del cliente” como crashes de app, pantallas en blanco o flujos de checkout rotos por cambios de API.
Si buscas feedback aún más rápido, las plataformas sin código pueden reducir la deriva regenerando código limpio tras cambios. Cuando la lógica o los modelos de datos cambian, la regeneración ayuda a evitar la acumulación de parches que cambian el comportamiento accidentalmente.
Si construyes APIs y clientes con AppMaster, un próximo paso práctico es probar ahora creando una aplicación, modelando tus datos en el Data Designer (PostgreSQL), actualizando workflows en el Business Process Editor y luego regenerando y desplegando en tu nube (o exportando el código fuente). Empareja eso con comprobaciones de contrato en tu CI para que cada build regenerado siga demostrando que coincide con lo que web y móvil esperan.


