Artículo

Cómo diseñar APIs en las que los clientes puedan confiar: guía práctica desde el contrato

Cómo diseñar APIs en las que los clientes puedan confiar: guía práctica desde el contrato

Una buena API hace predecible la próxima acción del cliente. Diseña una inscripción a un curso con reintentos seguros, errores útiles y un plan de evolución.

10 min de lecturaIdioma: ES EspañolGratis0 aplausos0 comentarios
Opciones de lectura

Una API es una promesa para otro equipo. Una aplicación móvil, una integración externa o una versión futura de tu frontend pueden depender de su comportamiento. Cuando eso ocurre, cambiar el nombre de un campo ya no es una refactorización local. Por eso conviene definir primero el comportamiento, los fallos y los reintentos; el controlador viene después.

Diseñemos una API de inscripción a cursos. El estudiante consulta un curso, solicita una plaza y recibe un identificador y un estado. El curso puede estar completo; la petición puede repetirse; la red puede fallar después de guardar la inscripción. Esos casos normales revelan la calidad del diseño.

1. Escribe el recorrido y las reglas

El cliente muestra el curso, el estudiante autenticado solicita la inscripción y recibe una respuesta clara. Si hay un tiempo de espera, puede reintentar sin duplicar la inscripción. Establece reglas de servidor: una inscripción activa por estudiante y curso, una ventana de inscripción abierta y capacidad que nunca se excede. Si hay pago, decide cuándo se reserva la plaza y cuándo se libera si falla.

Comparte una solicitud y una respuesta de ejemplo con el equipo cliente antes de programar. Es más fácil corregir un estado ambiguo o un campo ausente en esta fase.

2. Organiza recursos según el trabajo

Solicitud Objetivo Respuesta habitual
GET /v1/courses/{courseId} Leer el curso 200 OK
GET /v1/courses?cursor=...&limit=20 Explorar cursos 200 OK
POST /v1/courses/{courseId}/enrollments Inscribirse 201 Created
GET /v1/enrollments/{enrollmentId} Ver el estado 200 OK
DELETE /v1/enrollments/{enrollmentId} Cancelar si se permite 204 No Content

Si el trabajo continúa en segundo plano, 202 Accepted con un recurso de estado puede representar mejor la realidad. Usa GET para lectura y POST para crear o iniciar una operación. Que ciertos métodos HTTP sean idempotentes no vuelve seguro automáticamente cualquier POST. Evita exponer nombres de controladores o tablas en la ruta pública.

3. Diseña petición y respuesta a la vez

POST /v1/courses/crs_42/enrollments HTTP/1.1
Authorization: Bearer <access-token>
Content-Type: application/json
Idempotency-Key: 9bfa06f8-3eb5-4d5d-85cd-43b02b56bf11

{"source":"course_page"}

Obtén la identidad del estudiante de la credencial validada, no de un learnerId editable en el cuerpo. Una respuesta posible:

HTTP/1.1 201 Created
Location: /v1/enrollments/enr_7f3
Content-Type: application/json

{"id":"enr_7f3","courseId":"crs_42","status":"confirmed","createdAt":"2026-09-29T10:30:00Z"}

Documenta si los ID son opacos, los cambios posibles de estado y qué campos admiten null. No devuelvas la fila completa de la base de datos con notas internas o datos de otros alumnos. Para listas, usa un sobre consistente como data y page.nextCursor; especifica filtros y orden. Un cursor sin orden estable puede omitir o repetir elementos.

4. Convierte los errores en información útil

«Algo salió mal» no indica qué hacer. Distingue un curso cerrado de una sesión caducada, una falta de permiso y un fallo del servidor. RFC 9457 Problem Details ofrece un formato común:

{
  "type": "https://api.example.com/problems/enrollment-closed",
  "title": "Enrollment is closed",
  "status": 409,
  "detail": "This course stopped accepting enrollments."
}

En producción, type debe apuntar a una definición real. Documenta también los errores por campo. No muestres trazas, mensajes SQL ni secretos; conserva diagnósticos en registros seguros con un ID de correlación. Acordad el uso de 401 para autenticación, 403 para permiso, 404 según la política de visibilidad, 409 para conflicto y 429 para límites de frecuencia.

5. Prepara reintentos y concurrencia

El servidor puede confirmar la inscripción y perderse la respuesta. Con Idempotency-Key, el cliente envía una clave única para ese intento; el servidor guarda el resultado y lo devuelve ante la misma clave y petición. Rechaza la clave reutilizada con otro contenido. Define alcance, duración y respuesta. No es una garantía automática de HTTP para POST.

Protege la regla en la base de datos con restricciones adecuadas al ciclo de vida. Si queda una plaza, dos solicitudes simultáneas no deben ocuparla ambas: usa una transacción o reserva segura y una prueba concurrente. Los webhooks y trabajos en cola también pueden repetirse; diseña su procesamiento para ello.

6. Separa autenticación de autorización

La primera responde «¿quién llama?»; la segunda «¿puede acceder a este recurso?». Un token válido no permite leer la inscripción de otro estudiante. Aplica reglas de alumno, docente y administrador en el servidor. No confíes en un rol enviado en el cuerpo. Evita registrar tokens y documenta cómo debe esperar el cliente después de 429, además de si el límite es por usuario, token o cuenta.

7. Documenta, prueba y prepara el cambio

Describe rutas, esquemas, seguridad, respuestas y ejemplos en OpenAPI. Pide a un desarrollador cliente que integre usando solo ese documento: sus dudas mostrarán huecos. Prueba 201, el mismo intento repetido, una clave reutilizada con otra petición, curso completo, acceso indebido, carrera por la última plaza y orden de paginación.

Una ruta /v1 no es por sí sola un plan de versiones. Mantén un registro de cambios, anuncia la retirada de funciones, observa los clientes antiguos y publica una guía de migración. No cambies silenciosamente el significado de un campo. Si agregas pending_payment, considera cómo reaccionarán clientes que solo conocen confirmed y cancelled.

Revisión antes de publicar

¿Entiende el cliente los éxitos y los fallos accionables? ¿Compruebas permisos sobre el recurso? ¿Qué ocurre al repetir o competir dos peticiones? ¿Están claros filtros, orden y paginación? ¿Coincide OpenAPI con el comportamiento? ¿Puedes investigar fallos sin exponer datos privados? ¿Hay plan para cambios?

Una API no inspira confianza porque el caso feliz funcione una vez. La inspira cuando el cliente puede recuperarse de un corte de red, manejar un curso lleno y seguir funcionando tras tu siguiente versión.

Referencias

Artículos destacados

Kafka en producción: particiones, lag, fiabilidad y respuesta a incidentes
EditorialES
12 minGratis

Kafka en producción: particiones, lag, fiabilidad y respuesta a incidentes

Una guía práctica para tomar decisiones de orden, capacidad y recuperación en Kafka, interpretar el lag y responder a fallos sin perder de vista el resultado de negocio.

Artículos de ingenieríaGuías de plataforma
0 aplausos
Leer
Laravel y Kafka sin eventos perdidos: outbox transaccional y consumidores idempotentes con PostgreSQL
EditorialES
11 minGratis

Laravel y Kafka sin eventos perdidos: outbox transaccional y consumidores idempotentes con PostgreSQL

Una confirmación en PostgreSQL y una publicación en Kafka no forman una transacción ordinaria. Aprende a evitar pérdidas y duplicación de efectos.

Artículos de ingenieríaGuías de plataforma
0 aplausos
Leer
Apache Kafka explicado: temas, particiones, grupos de consumidores y tu primer flujo de eventos
EditorialES
10 minGratis

Apache Kafka explicado: temas, particiones, grupos de consumidores y tu primer flujo de eventos

Sigue un evento de pedido desde el productor hasta varios consumidores y prueba en local cómo funcionan las particiones, el orden y la reproducción.

Artículos de ingenieríaGuías de plataforma
0 aplausos
Leer

Comentarios

0 comentarios

Todavía no hay comentarios aprobados. Las respuestas nuevas pueden esperar moderación.