Aikido

Cómo evitar romper contratos de API públicos: manteniendo la compatibilidad con versiones anteriores

Mantenibilidad

Regla

Evite romper público API pública.
Cambia a público API públicos que podría romper
existente cliente solicitudes son rompiendo cambios.
Piense en en la API contrato como a promesa - cambiando
en después de clientes dependen de que se rompe su código.

Lenguajes soportados: PHP, Java, C#, Python, JavaScript, TypeScript

Introducción

Las API públicas son contratos entre su servicio y sus consumidores. Una vez que los clientes dependen del formato de solicitud, la estructura de respuesta o el comportamiento de un endpoint, cambiarlo rompe su código. Los cambios disruptivos obligan a todos los clientes a actualizarse simultáneamente, lo cual a menudo es imposible cuando no se controlan los clientes. Las aplicaciones móviles no pueden ser actualizadas forzosamente, las integraciones de terceros necesitan tiempo de migración y los sistemas heredados pueden no actualizarse nunca.

Por qué es importante

Interrupción del cliente y confianza: Los cambios de API que rompen la compatibilidad causan fallos inmediatos en las aplicaciones cliente en producción. Los usuarios experimentan errores, pérdida de datos o interrupciones completas del servicio. Esto daña la confianza entre proveedores y consumidores de API, y viola el contrato implícito de que las API estables permanecen estables.

Costes de coordinación: Coordinar cambios disruptivos entre múltiples equipos de clientes es costoso y lento. Cada equipo necesita tiempo para actualizar el código, probar los cambios y desplegar. Para APIs públicas con clientes desconocidos (aplicaciones móviles, integraciones de terceros), la coordinación es imposible.

Proliferación de versiones: Los cambios disruptivos mal gestionados llevan a mantener múltiples versiones de API simultáneamente. Cada versión requiere rutas de código, pruebas, documentación y correcciones de errores separadas, multiplicando exponencialmente la carga de mantenimiento.

Ejemplos de código

❌ No conforme:

// Version 1: Original API
app.get('/api/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({ id: user.id, name: user.name });
});

// Version 2: Breaking change - renamed field
app.get('/api/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({
        id: user.id,
        fullName: user.name  // Breaking: 'name' renamed to 'fullName'
    });
});

Por qué está mal: Renombrar 'name' a 'fullName' rompe todos los clientes existentes que esperan el campo 'name'. El código del cliente que acceda a response.name recibirá 'undefined', causando errores. Este cambio obliga a todos los clientes a actualizarse simultáneamente o fallar.

✅ Conforme:

// Version 2: Additive change - keeps old field, adds new
app.get('/api/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({
        id: user.id,
        name: user.name,           // Keep for backward compatibility
        fullName: user.name        // Add new field (deprecated 'name')
    });
});

// Or use API versioning
app.get('/api/v2/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({ id: user.id, fullName: user.name });
});

¿Por qué esto importa? Manteniendo lo antiguo nombre el campo mantiene la compatibilidad con versiones anteriores mientras añade nombre completo para nuevos clientes. Alternativamente, creando un nuevo endpoint versionado (/api/v2/) permite cambios disruptivos sin afectar a los clientes existentes que aún utilizan /api/v1/.

Conclusión

Evolucione las APIs mediante cambios aditivos: añada nuevos campos, nuevos endpoints, añada parámetros opcionales. Cuando los cambios disruptivos sean inevitables, utilice el versionado de API para ejecutar versiones antiguas y nuevas de forma concurrente. Depreque campos antiguos con plazos claros y guías de migración antes de eliminarlos.

Preguntas frecuentes

¿Tiene preguntas?

¿Qué cambios se consideran disruptivos?

Eliminar campos de las respuestas, renombrar campos, cambiar tipos de campo (de cadena a número), hacer que los parámetros opcionales sean obligatorios, cambiar los códigos de estado HTTP para condiciones existentes, alterar los requisitos de autenticación y modificar los formatos de respuesta de error. Añadir nuevos parámetros de solicitud obligatorios o eliminar completamente los endpoints también son cambios disruptivos.

¿Cómo añado nuevos campos obligatorios sin afectar a los clientes?

Haz que el nuevo campo sea opcional inicialmente con un valor predeterminado sensato. Documenta el cambio y da tiempo a los clientes para que lo adopten. Después de un tiempo suficiente (6-12 meses para APIs públicas), haz que el campo sea obligatorio en una nueva versión de la API. Nunca hagas obligatorios campos opcionales existentes sin versionado.

¿Cuál es la diferencia entre el versionado de API y la deprecación?

El versionado crea un nuevo endpoint (/v2/users) junto al antiguo, permitiendo que ambos coexistan. La deprecación marca un endpoint o campo antiguo como obsoleto, manteniéndolo funcional, con un cronograma para su eventual eliminación. Utilice el versionado para cambios importantes y la deprecación para la retirada gradual de características menores.

¿Durante cuánto tiempo debo mantener las versiones de API obsoletas?

Para las API públicas, mantenga las versiones obsoletas durante al menos 12-18 meses. Para las API internas, coordine con los equipos de clientes para establecer un cronograma de migración. Siempre proporcione un aviso anticipado (mínimo de 3 a 6 meses) antes de eliminar endpoints obsoletos. Supervise las métricas de uso para asegurarse de que los clientes hayan migrado antes del cierre.

¿Puedo cambiar el orden de los campos de respuesta?

Sí, el orden de los campos de un objeto JSON no forma parte del contrato de la API. Los clientes bien implementados parsean JSON por nombre de campo, no por posición. Sin embargo, prueba a fondo, ya que algunos clientes mal implementados podrían depender del orden de los campos. Para los arrays, el orden suele importar y no debería cambiar a menos que esté documentado.

¿Cómo versiono APIs sin cambios en la ruta de la URL?

Utilice encabezados HTTP: Accept: application/vnd.myapi.v2+json o encabezados personalizados como API-Version: 2. Los parámetros de consulta también funcionan: /api/users?version=2. La negociación de contenido a través de encabezados es más limpia pero más difícil de probar en navegadores. Elija una estrategia y úsela de forma consistente.

Asegúrate ahora.

Proteja su código, la nube y el entorno de ejecución en un único sistema central.
Encuentre y corrija vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.