¿Cómo evolucionas una API sin romper a los clientes existentes?
Cada campo que agregas es gratis; cada campo que quitas, renombras o le cambias el tipo es una promesa rota con alguien que probablemente nunca conociste — evolucionar bien una API significa tratar el contrato como público aunque no lo sea.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cómo evolucionas una API sin romper a los clientes existentes?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Por qué los entrevistadores hacen esta pregunta
Cualquiera puede diseñar la primera versión de una API. Lo que distingue a un ingeniero senior es qué pasa en la versión dos, la tres, y en cada cambio incremental después de eso — porque para entonces, clientes reales que no controlas del todo (una app móvil que no puedes forzar a actualizar, la integración de un partner, un servicio interno a tres equipos de distancia) ya dependen de la forma exacta de lo que lanzaste. Esta pregunta comprueba si piensas en el cuerpo de una respuesta como una promesa hecha a un desconocido, o como un detalle de implementación que eres libre de reordenar.
#La ley de Postel como principio operativo
El planteo clásico —"sé conservador en lo que envías, liberal en lo que aceptas"— se traduce directamente en disciplina de diseño de APIs. Del lado del servidor, "conservador en lo que envías" significa no quitar, renombrar ni retipar jamás algo que un cliente ya podría estar leyendo, porque no puedes verificar que nadie dependa de ello; del lado del cliente, "liberal en lo que aceptas" significa que un cliente bien construido ignora los campos que no reconoce y tolera que falten campos opcionales, en vez de fallar ante cualquier cosa inesperada. Ambas mitades importan — un servidor disciplinado con un cliente frágil igual se romperá ante un cambio aditivo perfectamente seguro, por eso el "lector tolerante" es tanto una disciplina de ingeniería de cliente como el versionado lo es de servidor.
#La taxonomía real: aditivo vs. disruptivo
| Seguro (aditivo) | Disruptivo (breaking) |
|---|---|
| Agregar un nuevo campo opcional en la respuesta | Quitar un campo, incluso uno que "parece no usarse" |
| Agregar un nuevo parámetro opcional en la solicitud | Renombrar un campo |
| Agregar un nuevo endpoint | Cambiar el tipo de un campo (string → number) |
| Agregar un nuevo valor de enum, sin default, a una solicitud que el cliente ya envía | Agregar un nuevo valor de enum a una respuesta sobre la que el cliente hace switch exhaustivo |
| Relajar una regla de validación (aceptar más cosas) | Endurecer una regla de validación (rechazar lo que antes era válido) |
| Volver opcional un campo de solicitud que era obligatorio (con un default sensato) | Volver obligatorio un campo de solicitud que era opcional |
| Agregar un nuevo header de respuesta | Cambiar un valor por defecto (tamaño de página, orden, zona horaria) sin bandera |
| Deprecar con headers de advertencia, comportamiento anterior intacto | Cambiar los códigos de estado de un caso de éxito/error existente |
#Versionado: elige la válvula de escape que de verdad necesitarás
La disciplina de solo-aditivo retrasa mucho la necesidad de subir de versión, pero no la elimina — eventualmente un cambio genuinamente disruptivo (una corrección de seguridad, un error de modelado que hay que arreglar) es inevitable. Las tres estrategias comunes tienen compromisos distintos:
| Estrategia | Ejemplo | Ventaja | Desventaja |
|---|---|---|---|
| Ruta URI | /v2/orders | Obvia, cacheable, fácil de enrutar en el gateway | Fomenta "bifurcar todo" en vez de cambios mínimos y focalizados |
| Header | Api-Version: 2 | Mantiene las URLs estables, encaja con la idea de identidad de recurso de REST | Fácil de olvidar, más difícil de probar/cachear/depurar desde una barra de navegador |
| Tipo de medio | Accept: application/vnd.shop.v2+json | La más "correcta" según la negociación de contenido de HTTP | La menos ergonómica para los consumidores, poco usada fuera de shops puristas de API |
Cualquiera sea el mecanismo que elijas, el objetivo es necesitarlo lo menos posible — la mayoría de las conversaciones de "¿necesitamos v3?" en realidad se resuelven al darse cuenta de que el cambio es aditivo después de todo, o aislando el único campo disruptivo detrás de uno nuevo opcional y deprecando el viejo con su propio cronograma en vez de bifurcar todo el recurso.
#La deprecación es un proceso, no un header
Anunciar bien un cambio disruptivo es lo que realmente protege a los clientes, no el mecanismo de versionado en sí. Una deprecación responsable se comunica por varios canales redundantes — una entrada en el changelog, contacto directo con los consumidores conocidos si es posible identificarlos, y señales legibles por máquina en la propia respuesta:
El header Deprecation señala "esto todavía funciona hoy, pero no debería usarse en código nuevo", mientras que el header Sunset (RFC 8594) da una fecha concreta después de la cual el comportamiento viejo puede dejar de funcionar por completo — ambos son verificables por herramientas automatizadas del lado del consumidor, no solo legibles por un humano que hojea la documentación.
#Detectar rupturas accidentales antes de que se publiquen
Nada de esto funciona si un cambio disruptivo puede llegar a producción sin que nadie lo note hasta que se disparan los reportes de fallos de un cliente. Esa brecha se cierra haciendo que la disciplina de la sección anterior sea exigible y no solo aspiracional: los contract tests (orientados al proveedor vía OpenAPI, u orientados al consumidor vía algo como Pact) corren en el CI contra la implementación real, y una herramienta de diff de esquema compara cada spec nueva contra la última publicada, haciendo fallar el build automáticamente cuando un campo desaparece, un tipo se restringe, o un campo antes opcional se vuelve obligatorio. Trata esa falla exactamente como una prueba unitaria en rojo — un ingeniero tiene que anularla conscientemente (subir la versión mayor, actualizar el changelog, arrancar el reloj de deprecación), nunca dejarla pasar en silencio.
🧠 Check your understanding
0/2 · 0/2 answered1. Tu campo OrderStatus puede ser pending, paid, shipped o cancelled. Agregas un quinto valor, refunded, en la respuesta. ¿Por qué esto puede romper clientes existentes aunque no se haya quitado nada?
2. ¿Cuál de estas es la forma más segura de comunicar que un endpoint se eliminará en 90 días, sin romper a nadie hoy?