Convenciones de rutas: colecciones y elementos
Al modelar rutas REST, el objetivo es que la URL describa recursos (sustantivos) y su estructura (colecciones, elementos y relaciones) de forma predecible. Una convención consistente reduce ambigüedades, facilita el consumo por clientes y evita que la API “se vuelva única” en cada endpoint.
Colecciones en plural
Use sustantivos en plural para representar colecciones. Esto hace que sea evidente que el recurso puede listar/crear elementos.
/users/orders/invoices
Elementos con identificador
Para un elemento específico, agregue un identificador como segmento de ruta.
/users/{userId}/orders/{orderId}
El identificador debe ser opaco para el cliente cuando sea posible (por ejemplo, UUID). Si usa IDs numéricos, mantenga el formato estable y no “codifique” significado adicional en la ruta.
Relaciones y pertenencia: anidamiento controlado
El anidamiento expresa pertenencia o contexto: “estos pedidos pertenecen a este usuario”. Es útil cuando el recurso hijo no tiene sentido sin el padre o cuando el acceso está naturalmente acotado por el padre.
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
Ejemplo típico de pertenencia
/users/{userId}/orders(colección de pedidos del usuario)/users/{userId}/orders/{orderId}(un pedido específico del usuario)
Cuándo anidar y cuándo no
Use anidamiento cuando:
- La relación es fuerte (composición o pertenencia clara).
- Necesita restringir el ámbito por permisos o multitenencia (p. ej., un usuario solo puede ver sus pedidos).
- El recurso hijo se identifica naturalmente dentro del contexto del padre.
Evite anidar cuando:
- El recurso hijo es global y puede consultarse sin el padre (p. ej.,
/orders/{orderId}existe por sí mismo). - El anidamiento empieza a crecer en profundidad y complejidad.
- La relación es más bien una asociación (muchos-a-muchos) y no “pertenencia”.
Límites de profundidad y alternativas al anidamiento
Una regla práctica común es limitar el anidamiento a 1 nivel (padre/hijo) y, como máximo, 2 niveles en casos excepcionales. A partir de ahí, la ruta se vuelve difícil de mantener, de documentar y de consumir.
Ejemplos de profundidad excesiva (a evitar)
/companies/{companyId}/users/{userId}/orders/{orderId}/items/{itemId}
En su lugar, combine rutas más planas con filtros, parámetros de consulta y enlaces.
Alternativa 1: parámetros de consulta para filtrar por relación
Si orders es un recurso global, puede filtrar por usuario:
/orders?userId={userId}/orders?userId={userId}&status=paid
Esto evita rutas profundas y mantiene un punto de entrada consistente para búsquedas.
Alternativa 2: subrecursos “de relación” explícitos
Para relaciones muchos-a-muchos o asociaciones, considere un recurso de relación:
/users/{userId}/roles(roles asignados)/user-roles?userId={userId}(colección de asignaciones)
La elección depende de si la relación tiene atributos propios (por ejemplo, fecha de asignación). Si los tiene, un recurso de relación suele ser más claro.
Alternativa 3: enlaces (HATEOAS ligero) para navegar
Sin entrar en formalismos, es muy útil devolver enlaces para que el cliente descubra rutas relacionadas sin construirlas manualmente.
{ "id": "u_123", "name": "Ada", "links": { "self": "/users/u_123", "orders": "/users/u_123/orders" }}Esto ayuda a mantener la estabilidad: si en el futuro cambia la forma de acceder a orders, puede ajustar el enlace sin romper clientes que lo consumen.
Coherencia de nombres: kebab-case vs snake_case
Defina una convención y aplíquela en toda la API. En rutas, lo más importante es la consistencia (no mezclar estilos).
Recomendación práctica
- Para segmentos de ruta con varias palabras, use kebab-case:
/payment-methods,/order-items. - Evite mezclar con snake_case en rutas:
/payment_methods.
Si su organización ya usa snake_case en rutas por legado, manténgalo, pero no lo mezcle con kebab-case. Reserve la discusión de estilos para un estándar interno y documente la decisión.
Tabla de consistencia de nombres
| Concepto | Consistente | Inconsistente (evitar) |
|---|---|---|
| Colección | /users | /user |
| Elemento | /users/{userId} | /users?id={userId} (para obtener un elemento) |
| Segmento compuesto | /payment-methods | /payment_methods y /paymentMethods mezclados |
| Anidamiento | /users/{userId}/orders | /users/{userId}/order-list |
Estabilidad de rutas: cómo evitar romper clientes
Las rutas deben ser estables en el tiempo. Cambios frecuentes en URLs obligan a migraciones costosas.
Buenas prácticas para estabilidad
- No incluya detalles de implementación en la ruta: evite
/sql/,/legacy/,/v2new/. - Evite rutas “verbales” que reflejen acciones cambiantes:
/users/{id}/getOrders. - Use nombres de dominio que sobrevivan a cambios internos:
/ordersen lugar de/purchasessi el negocio lo llama “orders” y es estable. - Planifique alias o redirecciones si debe renombrar: mantenga temporalmente la ruta antigua y devuelva enlaces a la nueva.
Ejemplos comparativos: rutas correctas e incorrectas
Colecciones y elementos
- Correcta:
/products - Incorrecta:
/getProducts - Correcta:
/products/{productId} - Incorrecta:
/product/{productId}(singular si el resto está en plural)
Relaciones y anidamiento
- Correcta:
/users/{userId}/orders(pertenencia clara) - Incorrecta:
/users/{userId}/orders/{orderId}/payments/{paymentId}/refunds/{refundId}(profundidad excesiva) - Alternativa correcta (más plana):
/refunds?paymentId={paymentId}o/refunds/{refundId}con enlace desde/payments/{paymentId}
Consistencia de estilo
- Correcta (kebab-case):
/order-items - Incorrecta (mezcla):
/order_itemsen un módulo y/order-itemsen otro
Evitar “acciones” en la ruta
- Correcta:
/orders/{orderId}/status(si el estado es un subrecurso) - Incorrecta:
/orders/{orderId}/changeStatus
Guía práctica paso a paso para diseñar rutas de recursos y relaciones
Paso 1: liste recursos principales (colecciones)
Escriba los sustantivos del dominio que el cliente necesita manipular o consultar. Ejemplo: users, orders, products, payments.
Paso 2: defina identificadores y formato
Decida el patrón de IDs por recurso (UUID, numérico, prefijo). Manténgalo consistente y documente ejemplos: u_123, ord_456.
Paso 3: identifique relaciones de pertenencia (candidatas a anidamiento)
Pregunte: “¿tiene sentido listar X sin Y?” Si no, anide: /users/{userId}/orders. Si sí, mantenga X como recurso global y use filtros o enlaces.
Paso 4: aplique un límite de profundidad
Establezca una regla interna (por ejemplo, máximo 1 nivel) y úsela como criterio de revisión. Si necesita más, reevalúe: ¿puede resolverse con ?filter o con un recurso de relación?
Paso 5: estandarice el estilo de nombres
Elija kebab-case o snake_case para rutas y aplíquelo a todos los segmentos compuestos. Cree una lista de nombres canónicos (glosario) para evitar sinónimos: orders vs purchases.
Paso 6: valide estabilidad y crecimiento
Simule cambios futuros: ¿qué pasa si orders se asocia a organizations además de users? Una ruta plana /orders/{orderId} con enlaces a su propietario suele resistir mejor que rutas profundamente contextuales.
Checklist de consistencia para revisar rutas
- ¿Todas las colecciones están en plural?
- ¿Los elementos se acceden como
/{collection}/{id}y no con parámetros para “obtener uno”? - ¿El anidamiento se usa solo para pertenencia clara y no supera el límite acordado?
- ¿Existen alternativas planas con parámetros de consulta para búsquedas y filtros?
- ¿Se evita mezclar kebab-case y snake_case en rutas?
- ¿Los nombres de recursos son consistentes (sin sinónimos) en toda la API?
- ¿Las rutas evitan verbos/acciones (
/get,/create,/do)? - ¿Las rutas no exponen detalles de implementación y son estables ante cambios internos?
- ¿Las respuestas incluyen enlaces útiles para navegar a recursos relacionados cuando aplica?