Fundamentos del diseño de APIs REST orientado a recursos

Capítulo 1

Tiempo estimado de lectura: 10 minutos

+ Ejercicio

REST en la práctica: recursos, representaciones y relaciones

En diseño REST, el foco no está en “llamar funciones” sino en exponer un modelo de recursos del dominio. Un recurso es cualquier “cosa” del dominio que tenga identidad estable y pueda referenciarse (normalmente con una URL). El cliente no manipula el recurso “en sí”, sino una representación del recurso (por ejemplo JSON) que describe su estado y enlaces relevantes. Además, los recursos no viven aislados: existen relaciones (pertenencias, asociaciones, dependencias) que conviene expresar con URLs y vínculos.

Recurso vs representación

  • Recurso: concepto del dominio con identidad (p. ej., un pedido #123, un cliente #88, una factura #F-2026-01).
  • Representación: el “formato” que viaja por la red (p. ej., JSON con campos del pedido). Puede variar sin que cambie el recurso.
  • Relaciones: conexiones navegables entre recursos (p. ej., un pedido pertenece a un cliente; un pedido tiene líneas; una factura se emite a partir de un pedido).

Una forma práctica de comprobar si algo es un recurso: ¿puedo enlazarlo, listarlo, consultarlo y su identidad tiene sentido para el negocio?

Relaciones como URLs y vínculos

Las relaciones pueden expresarse de dos maneras complementarias:

  • Subrecursos (estructura en la ruta): cuando la relación es de contención/jerarquía fuerte. Ej.: /customers/{customerId}/orders.
  • Vínculos en la representación: cuando quieres guiar navegación o expresar asociaciones sin acoplar todo a la ruta. Ej.: incluir links con URLs a recursos relacionados.
{ "id": "ord_123", "status": "paid", "total": 125.50, "customerId": "cus_88", "links": { "self": "/orders/ord_123", "customer": "/customers/cus_88", "items": "/orders/ord_123/items", "invoice": "/invoices/inv_9001" } }

Cómo identificar recursos a partir del dominio

El punto de partida no es la lista de endpoints, sino los requisitos funcionales y el lenguaje del negocio. A partir de ahí, se extraen candidatos a recursos y se decide su forma (colección, elemento, subrecurso, relación).

Paso 1: extraer sustantivos y “cosas con identidad”

De historias de usuario o requisitos, subraya sustantivos y objetos que el negocio reconoce. Ejemplo de requisitos (dominio: e-commerce):

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

Descargar la aplicación

  • “Un cliente puede ver sus pedidos y el detalle de cada pedido.”
  • “Un cliente puede añadir productos al carrito y confirmar la compra.”
  • “El sistema genera un reporte diario de ventas por categoría.”

Candidatos iniciales: customers, orders, order-items, carts, products, reports, categories.

Paso 2: clasificar candidatos (entidad, subrecurso, relación)

  • Entidades principales: tienen ciclo de vida propio y suelen existir “por sí mismas” (clientes, productos, pedidos).
  • Subrecursos: existen dentro del contexto de un padre (líneas de pedido dentro de un pedido; items del carrito dentro del carrito).
  • Relaciones: vínculos entre entidades (pedido → cliente; pedido → factura; producto → categoría). A veces se modelan como recursos propios si tienen atributos (p. ej., una “membresía” con fecha de alta, rol, estado).

Paso 3: decidir colecciones y elementos

En REST, es común distinguir:

  • Colección: conjunto de recursos del mismo tipo. Ej.: /orders, /customers.
  • Elemento: un recurso concreto dentro de una colección. Ej.: /orders/{orderId}.

Regla práctica: si puedes “listar” y “crear” en un conjunto, probablemente necesitas una colección; si puedes “consultar/actualizar” un objeto concreto, necesitas el elemento.

TipoEjemploCuándo usar
Colección/ordersListar pedidos, crear un pedido
Elemento/orders/{orderId}Consultar/actualizar un pedido específico
Subcolección/customers/{id}/ordersListar pedidos de un cliente (contexto fuerte)
Subelemento/orders/{id}/items/{itemId}Operar sobre una línea concreta

Paso 4: definir atributos (estado) y límites

Para cada recurso, define atributos que representen su estado y evita mezclar responsabilidades. Preguntas útiles:

  • ¿Qué campos son esenciales para identificar y mostrar el recurso?
  • ¿Qué campos cambian con el tiempo (estado)?
  • ¿Qué campos son derivados (se pueden calcular) y conviene exponer o no?
  • ¿Qué datos pertenecen a otro recurso (y deberían ser un vínculo en lugar de duplicación)?

Ejemplo (pedido):

  • Propios: id, status, createdAt, total, currency
  • Referencias: customerId y enlace a /customers/{id}
  • Subrecursos: /orders/{id}/items, /orders/{id}/payments

Paso 5: modelar relaciones navegables (vínculos)

Además de la ruta, incluye vínculos que ayuden a descubrir acciones válidas sin convertir la API en un “mapa de funciones”. Un patrón simple es un objeto links con URLs relevantes (self, related). En dominios complejos, también puedes incluir metadatos del vínculo (tipo, método sugerido), pero mantén consistencia.

Criterios para decidir: recurso vs acción

Una fuente común de diseños tipo RPC es convertir cada verbo del negocio en un endpoint (/doSomething, /calculate, /confirmOrder). En REST, primero intentas expresar el cambio como una transición de estado de un recurso o la creación de un recurso nuevo.

Checklist práctico

  • ¿Hay un “resultado” con identidad? Si el resultado se puede consultar después, probablemente es un recurso. Ej.: “generar factura” → /invoices (se crea una factura) en vez de /generateInvoice.
  • ¿Es un cambio de estado de un recurso existente? Modela el estado como atributo y actualízalo. Ej.: confirmar pedido → actualizar status del pedido o crear un recurso “confirmación” si necesitas auditoría.
  • ¿Es una operación efímera sin identidad? Aun así, a menudo puedes modelarla como recurso “proceso” o “job” si es asíncrona. Ej.: exportación → /exports (creas un export y luego consultas su estado/descarga).
  • ¿El verbo es del dominio o es técnico? Verbos técnicos (“validate”, “process”) suelen esconder recursos. Pregunta: ¿qué entidad del negocio se valida/procesa?

Ejemplos de transformación de “acciones” a recursos

RequisitoDiseño tipo RPC (evitar)Diseño orientado a recursos
Confirmar un pedidoPOST /orders/{id}/confirmPATCH /orders/{id} con {"status":"confirmed"} o POST /order-confirmations con referencia al pedido
Reembolsar un pagoPOST /payments/{id}/refundPOST /refunds con {"paymentId":"...","amount":...}
Exportar ventasPOST /exportSalesPOST /exports (crea job) y GET /exports/{id} (estado/URL de descarga)
Calcular impuestosPOST /calculateTaxSi es parte del pedido: exponer tax en /orders/{id}; si es simulación: POST /tax-quotes

Nota: a veces un endpoint “verbal” es aceptable si representa un subrecurso claramente acotado y estable, pero el objetivo es que el modelo no se convierta en un catálogo de métodos.

Cuándo usar endpoints específicos como /reports sin caer en RPC

Hay casos donde el dominio incluye “artefactos” que no son entidades transaccionales típicas, como reportes, dashboards, exportaciones o agregados. Se pueden diseñar de forma REST si los tratas como recursos con identidad, estado y/o parámetros bien definidos.

Patrones recomendados

  • Reportes como recursos consultables: GET /reports/sales-daily?date=2026-02-01. Aquí sales-daily es un tipo de reporte (recurso lógico) y la consulta define la instancia de la representación.
  • Reportes materializados (con identidad): POST /reports para crear un reporte (job), luego GET /reports/{reportId} para ver estado y resultado. Útil si tarda o si quieres auditoría.
  • Agregados del dominio: si el negocio habla de “resumen de cuenta”, puede ser un recurso: GET /customers/{id}/account-summary.

Señales de que estás cayendo en RPC

  • Rutas con verbos genéricos: /runReport, /getSales, /processEndOfDay.
  • Un solo endpoint que recibe un parámetro action y hace cosas distintas.
  • La mayoría de endpoints son “comandos” sin recursos navegables ni resultados persistentes.

Guía paso a paso: de requisitos a inventario de recursos

Usa este procedimiento para convertir requisitos en un inventario inicial de recursos, con atributos y vínculos. El objetivo no es “cerrar” el diseño, sino producir un mapa consistente para iterar.

Paso 1: listar casos de uso en lenguaje del negocio

Escribe 6–10 frases del tipo “Como X, quiero Y para Z”. Ejemplo (plataforma de suscripciones):

  • Como usuario, quiero ver los planes disponibles.
  • Como usuario, quiero suscribirme a un plan.
  • Como usuario, quiero ver el estado de mi suscripción y mi próxima fecha de cobro.
  • Como usuario, quiero cancelar mi suscripción.
  • Como admin, quiero ver un reporte mensual de ingresos.

Paso 2: extraer candidatos a recursos (sustantivos) y eventos

  • Recursos: plans, subscriptions, users, invoices, reports.
  • Eventos/acciones: “suscribirse”, “cancelar”. Intenta mapearlos a cambios de estado o creación de recursos.

Paso 3: definir colecciones, elementos y subrecursos

  • /plans y /plans/{planId}
  • /subscriptions y /subscriptions/{subscriptionId}
  • Si la suscripción pertenece fuertemente al usuario: /users/{userId}/subscriptions (y opcionalmente también /subscriptions/{id} si se accede globalmente)
  • Facturas de una suscripción: /subscriptions/{id}/invoices

Paso 4: proponer atributos mínimos por recurso

RecursoAtributos sugeridosNotas
Planid, name, price, currency, billingPeriod, featuresGeneralmente de solo lectura para usuarios
Subscriptionid, userId, planId, status, startedAt, nextBillingAt, cancelAtPeriodEndstatus modela “cancelada/activa/past_due”
Invoiceid, subscriptionId, amount, currency, status, issuedAt, dueAtPuede incluir enlace a descarga
Reportid (si materializado), type, period, status, createdAt, resultUrlSi es síncrono, puede ser solo GET con query

Paso 5: definir vínculos clave (navegación)

Para cada recurso, define 3–6 vínculos que un cliente necesitará con frecuencia.

{ "id": "sub_10", "status": "active", "planId": "plan_basic", "userId": "usr_7", "nextBillingAt": "2026-03-01", "links": { "self": "/subscriptions/sub_10", "plan": "/plans/plan_basic", "user": "/users/usr_7", "invoices": "/subscriptions/sub_10/invoices" } }

Paso 6: resolver “acciones” con decisiones explícitas

Para cada verbo del negocio, decide una de estas opciones y documenta el porqué:

  • Cambio de estado en un recurso existente (p. ej., cancelar → status o cancelAtPeriodEnd).
  • Creación de un recurso que representa el resultado (p. ej., suscribirse → crear subscription).
  • Creación de un recurso de proceso si es asíncrono (p. ej., generar reporte → crear report con status).

Ejemplo de mapeo:

  • “Suscribirse a un plan” → POST /subscriptions con {"userId":"usr_7","planId":"plan_basic"}
  • “Cancelar suscripción” → PATCH /subscriptions/{id} con {"cancelAtPeriodEnd":true} (o {"status":"canceled"} si es inmediata)
  • “Reporte mensual de ingresos” → GET /reports/revenue-monthly?month=2026-01 o POST /reports con {"type":"revenue-monthly","month":"2026-01"}

Ejercicio guiado: convertir requisitos en inventario de recursos

Objetivo: producir un inventario de recursos con (1) nombre, (2) colección/elemento, (3) atributos, (4) relaciones/vínculos, (5) notas de “acción vs recurso”.

Enunciado

Supón que estás diseñando una API para una biblioteca digital:

  • Los usuarios pueden buscar libros por título/autor.
  • Los usuarios pueden ver el detalle de un libro y su disponibilidad.
  • Los usuarios pueden reservar un libro si no está disponible.
  • Los usuarios pueden ver sus reservas activas y cancelarlas.
  • Los bibliotecarios generan un reporte semanal de préstamos.

Parte A: extracción de recursos (10 minutos)

  • Lista sustantivos: libros, autores, usuarios, reservas, préstamos, reportes.
  • Marca cuáles tienen identidad clara: libro, usuario, reserva, préstamo, reporte (posible), autor (posible).

Parte B: inventario inicial (15 minutos)

Completa una tabla como esta (rellena con tus decisiones):

RecursoColecciónElementoAtributos mínimosVínculos/relacionesNotas
Book/books/books/{bookId}id, title, authors, availabilityself, authors, reservationsBúsqueda con query en colección
Reservation/reservations o /users/{id}/reservations/reservations/{reservationId}id, userId, bookId, status, createdAtbook, user“Reservar” = crear reserva
Report/reports o /reports/loans-weekly/reports/{reportId} (si materializado)type, period, status, resultselfDecidir síncrono vs job

Parte C: decisiones “recurso vs acción” (10 minutos)

  • “Buscar libros” → no es un recurso nuevo: es una consulta sobre /books (p. ej., GET /books?query=...).
  • “Reservar un libro” → crear reservation (p. ej., POST /reservations con bookId y userId).
  • “Cancelar reserva” → cambio de estado de reservation (p. ej., PATCH /reservations/{id} con {"status":"canceled"}).
  • “Generar reporte semanal” → si tarda, crear recurso report (job) y consultar su estado.

Parte D: revisión de consistencia (5 minutos)

  • ¿Las rutas son sustantivos en plural para colecciones?
  • ¿Las relaciones importantes tienen vínculo o subrecurso?
  • ¿Las “acciones” quedaron expresadas como creación/cambio de estado?
  • ¿Hay endpoints que parecen funciones? Si sí, intenta re-modelarlos como recursos.

Ahora responde el ejercicio sobre el contenido:

Al diseñar una API REST orientada a recursos, ¿cuál es la forma más adecuada de modelar la operación “reservar un libro” cuando esa reserva debe poder consultarse y cancelarse después?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

Si el resultado tiene identidad y debe consultarse o cambiar de estado (p. ej., cancelar), conviene modelarlo como un recurso propio. “Reservar” se expresa como creación de Reservation y la cancelación como transición de estado del recurso.

Siguiente capítulo

Modelado de recursos, colecciones y relaciones en rutas REST

Arrow Right Icon
Portada de libro electrónico gratuitaDiseño de APIs REST: buenas prácticas, errores comunes y estándares
10%

Diseño de APIs REST: buenas prácticas, errores comunes y estándares

Nuevo curso

10 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.