Software Engineering22 de julio de 20268 min read

Diseñar API que los desarrolladores realmente disfrutan usar

Las mejores API parecen evidentes. Esta guía recorre las decisiones de diseño que convierten una interfaz técnica en algo a lo que los desarrolladores recurren una y otra vez.

Por Innovation T Team


La mejor API que hayas usado probablemente te dio la sensación de que leía tu mente. Adivinaste el endpoint y existía. Adivinaste el nombre del campo y era el correcto. Los errores te decían exactamente qué había salido mal. Esa sensación no es cuestión de suerte. Es el producto de decisiones de diseño deliberadas, tomadas por personas a quienes les importaba quien está al otro lado de la solicitud.

En Innovation T construimos e integramos API en proyectos web, móviles y de nube, y la misma lección sigue apareciendo: una API es un producto, y sus usuarios son desarrolladores. Trata su tiempo y su atención con la misma seriedad con la que tratas los de un usuario final, y la adopción llegará. Así se diseña una interfaz que la gente realmente disfruta usar.

Nomenclatura coherente de recursos

Una API es un vocabulario. Si ese vocabulario es incoherente, cada endpoint se convierte en una pequeña prueba de memoria. Elige convenciones claras y no las rompas nunca.

Usa sustantivos para los recursos, no verbos. El método HTTP ya lleva el verbo. Emplea nombres de recursos en plural, en minúsculas, separados por guiones, y anida las relaciones de forma predecible:

GET    /v1/customers
GET    /v1/customers/42
GET    /v1/customers/42/invoices
POST   /v1/customers/42/invoices
DELETE /v1/invoices/900

Evita mezclar userId, user_id y UserID en las cargas útiles. Elige un único estilo de escritura (camelCase o snake_case) y aplícalo a cada campo de cada respuesta. La coherencia vale más que cualquier elección aislada considerada "mejor", porque permite a los desarrolladores predecir lo que aún no han leído.

Códigos de estado sensatos

Los códigos de estado son la primera señal que lee un cliente, a menudo antes de analizar el cuerpo. Úsalos con honestidad.

  • 200 para una lectura o actualización correcta.
  • 201 para un recurso que acabas de crear, con una cabecera Location.
  • 202 cuando aceptaste un trabajo que finaliza de forma asíncrona.
  • 204 para una eliminación correcta sin cuerpo.
  • 400 para una entrada mal formada, 401 para credenciales ausentes o incorrectas, 403 para un usuario autenticado pero sin permiso.
  • 404 para un recurso que no existe, 409 para un conflicto como un duplicado.
  • 422 para solicitudes bien formadas que no superan las reglas de validación.
  • 429 cuando el cliente supera el límite de tasa.
  • 500 para tus propios errores, nunca para los del cliente.

El pecado capital es devolver un 200 OK con un error oculto en el cuerpo. Eso obliga a cada cliente a analizar las respuestas de éxito de forma defensiva y anula todo el sentido de los códigos de estado.

Cuerpos de error útiles

Un código de estado dice que algo salió mal. Un buen cuerpo de error dice qué, dónde y cómo corregirlo. Haz que los errores sean legibles por la máquina y por el humano al mismo tiempo:

{
  "error": {
    "type": "validation_error",
    "message": "The request could not be processed.",
    "fields": [
      { "name": "email", "issue": "must be a valid email address" },
      { "name": "age", "issue": "must be greater than or equal to 18" }
    ],
    "requestId": "req_8fa21c"
  }
}

El type estable permite a los clientes ramificar su código. El message ayuda a un humano que lee los registros. El arreglo fields convierte un rechazo vago en una lista de verificación accionable. El requestId permite a un desarrollador pegar una sola cadena en un ticket de soporte para que puedas encontrar la solicitud exacta en tus registros. Ese único campo ahorra horas a ambas partes.

Paginación y filtrado predecibles

Toda colección que pueda crecer debe paginarse desde el primer día. Añadir la paginación después es un cambio disruptivo que sorprende a todos.

La paginación basada en cursor es la opción más robusta para conjuntos de datos grandes o que cambian con frecuencia, porque no omite ni duplica filas cuando los datos se desplazan entre solicitudes:

{
  "data": [
    { "id": "inv_1", "amount": 1200 },
    { "id": "inv_2", "amount": 850 }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6Imludl8yIn0",
    "hasMore": true
  }
}

El cliente sigue pasando ?cursor=... hasta que hasMore sea falso. La paginación por desplazamiento (?page=3&limit=20) es más simple y adecuada para listas pequeñas y estables, pero se desvía cuando se insertan o eliminan filas a mitad del desplazamiento.

El filtrado merece la misma previsibilidad. Usa parámetros de consulta que se lean como lenguaje llano y documenta cada uno: ?status=paid&created_after=2026-01-01&sort=-amount. Un signo menos al inicio para el orden descendente es una pequeña convención, pero una vez que un desarrollador la aprende, funciona en toda tu API.

Idempotencia

Las redes fallan a mitad de camino. Un cliente envía una solicitud de pago, la conexión se cae antes de que llegue la respuesta y el cliente no tiene idea de si el cargo se realizó. Sin ayuda, la suposición segura (reintentar) genera cargos duplicados.

Las claves de idempotencia resuelven esto. El cliente genera una clave única y la envía como cabecera en cualquier solicitud que no sea naturalmente segura de repetir:

POST /v1/charges
Idempotency-Key: 5f2c1a90-payment-42

Tu servidor almacena la clave junto con el resultado de la primera solicitud. Si la misma clave llega de nuevo, devuelves la respuesta original en lugar de ejecutar la acción dos veces. GET, PUT y DELETE son idempotentes por definición. Es POST el que necesita esta protección, y ofrecerla indica que has pensado en serio en la fiabilidad en el mundo real. Esto importa aún más para clientes construidos como aplicaciones móviles con enfoque offline first (consulta /blog/offline-first-mobile-apps), donde las solicitudes se ponen en cola y se reproducen una vez que vuelve la conectividad.

Límites de tasa que comunican

Los límites de tasa protegen tu infraestructura, pero un 429 silencioso no enseña nada a los desarrolladores. Dile a cada cliente en qué situación se encuentra en cada respuesta:

RateLimit-Limit: 1000
RateLimit-Remaining: 12
RateLimit-Reset: 1753142400

Cuando realmente rechaces una solicitud, incluye una cabecera Retry-After para que los clientes puedan replegarse con elegancia en lugar de acosarte. Un cliente bien educado es una alianza, y la construyes dándole la información que necesita para comportarse bien.

Autenticación que se ajusta al caso de uso

Adapta el mecanismo a quien llama. Los tokens bearer de corta duración (tokens de acceso OAuth 2.0 o JWT) convienen a las aplicaciones orientadas al usuario, donde las sesiones caducan y se renuevan. Las claves de API convienen a las integraciones de servidor a servidor, donde un secreto de larga duración es aceptable. Sea cual sea tu elección, cumple tres reglas: exige HTTPS en todas partes, nunca aceptes credenciales en la cadena de consulta, donde se filtran a los registros, y devuelve 401 con una razón clara cuando la autenticación falla. La autenticación es donde la confianza se gana o se pierde, así que hazla aburrida y predecible.

Estrategia de versionado

El cambio es inevitable. Una estrategia de versionado es tu promesa de que el cambio no romperá las integraciones existentes sin previo aviso.

El versionado por URL (/v1/, /v2/) es el más visible y el más fácil de razonar, por lo que sigue siendo la opción predeterminada habitual. El versionado por cabecera mantiene las URL limpias pero oculta la versión, así que es más fácil de olvidar. Elijas lo que elijas, la disciplina importa más que el mecanismo: los cambios aditivos (nuevos campos opcionales, nuevos endpoints) son seguros y no requieren una nueva versión. Eliminar un campo, renombrarlo o cambiar un tipo es un cambio disruptivo que exige una nueva versión más una ventana de desactivación. Nunca reutilices en silencio un campo existente.

Garantías de estabilidad

Dile a los desarrolladores en qué pueden confiar. Publica qué partes de tu API son estables, cuáles están en beta y cuánto tiempo seguirá funcionando una versión obsoleta antes de retirarla. Una política de desactivación clara, por ejemplo seis meses de aviso con advertencias fechadas en las cabeceras de respuesta, convierte una migración temible en una tarea programada. Los desarrolladores construirán sobre una API en la que confían que se mantendrá estable mucho más de buena gana que sobre una que podría moverse bajo sus pies sin aviso.

Documentación y ejemplos excelentes

La documentación es donde los desarrolladores pasan la mayor parte de su tiempo con tu API, así que es donde el diseño rinde frutos o se derrumba. Las mejores documentaciones comparten unos rasgos: una solicitud lista para copiar y pegar por cada endpoint, un ejemplo de respuesta real junto a ella y campos claramente marcados como obligatorios u opcionales. Muestra la autenticación una sola vez, al principio, en un fragmento ejecutable. Ofrece un inicio rápido que lleve a un desarrollador a su primera llamada exitosa en menos de cinco minutos, porque ese primer éxito es lo que convierte a un lector curioso en un usuario comprometido. Una documentación interactiva que permita a alguien lanzar una solicitud real desde el navegador convierte la lectura en aprendizaje.

REST y las alternativas

REST es la opción predeterminada por una buena razón: se ajusta con limpieza a HTTP, es almacenable en caché y se entiende universalmente. La mayor parte de este artículo asume REST porque la mayoría de las API son REST.

No es la única opción. GraphQL permite a los clientes solicitar exactamente los campos que necesitan en un solo viaje de ida y vuelta, lo que brilla con datos ricos y anidados y con pantallas de aplicación que de otro modo se dispersarían en muchas llamadas REST, a costa de una complejidad de caché y una planificación de consultas más pesada en el lado del servidor. gRPC usa Protocol Buffers binarios sobre HTTP/2 y es excelente para el tráfico interno de servicio a servicio de alto rendimiento, aunque es menos amigable con los navegadores y la exploración casual. La elección correcta depende de tus consumidores. Una API pública para una audiencia amplia se inclina hacia REST; una aplicación móvil con necesidades de datos complejas quizá prefiera GraphQL; una flota de microservicios internos podría estandarizarse en gRPC. Si estás sopesando las fronteras de servicio y los estilos de comunicación, nuestra guía sobre el paso de /blog/monolith-to-microservices profundiza más en esas concesiones.

La lista de verificación de diseño de API

Pasa toda API nueva por esta lista antes de publicarla:

  1. ¿Se nombran los recursos con sustantivos coherentes, en plural y en minúsculas?
  2. ¿Es idéntico el estilo de escritura de los campos en cada endpoint?
  3. ¿Significa cada código de estado lo que debería, sin errores ocultos dentro de un 200?
  4. ¿Incluyen los cuerpos de error un tipo estable, un mensaje humano, los campos infractores y un identificador de solicitud?
  5. ¿Está paginada cada colección que puede crecer, con filtrado y ordenamiento documentados?
  6. ¿Están protegidas las operaciones inseguras con claves de idempotencia?
  7. ¿Exponen las respuestas cabeceras de límite de tasa y un Retry-After en caso de rechazo?
  8. ¿Se aplica la autenticación sobre HTTPS, con las credenciales fuera de las URL?
  9. ¿Existe una estrategia de versionado clara y una política de desactivación publicada?
  10. ¿Puede un desarrollador nuevo hacer una llamada exitosa desde la documentación en menos de cinco minutos?

Uniéndolo todo

Cada punto anterior se reduce a una sola idea: respetar el tiempo del desarrollador. La nomenclatura coherente le ahorra memoria, los códigos de estado honestos le ahorran conjeturas, los errores útiles le ahorran depuración, la idempotencia le ahorra desastres de duplicados y una buena documentación le ahorra frustración. Haz esto de forma constante y tu API dejará de ser un detalle técnico para convertirse en una razón por la que la gente te elige.

Si tu equipo está diseñando una API nueva, desenredando una heredada o decidiendo entre REST, GraphQL y gRPC, Innovation T puede ayudarte a sentar bien las bases. Descubre cómo trabajamos en nuestra página de servicios, o contáctanos para hablar de tu proyecto.

#diseño de API#REST#experiencia del desarrollador#ingeniería de software

¿Listo para construir con Innovation T?

Ya se trate de seguridad, crecimiento o ingeniería, nuestro equipo puede ayudarte a lograrlo con calidad.