Los URI (Uniform Resource Identifier) son la interfaz clave entre tu API y sus usuarios. Imagina que los URI son direcciones en un mapa que los usuarios (con su navegador) usarán para acceder a las funcionalidades de tu aplicación. Si tus URI son confusos, inconsistentes o mal pensados, los usuarios de la API sufrirán la misma frustración que sentimos cuando recorremos la ciudad entera para descubrir que la dirección no lleva a ningún lado.
URI bien diseñados:
- Mejoran la legibilidad y la previsibilidad de la API.
- Proporcionan consistencia y facilitan el mantenimiento.
- Ayudan a un desarrollador nuevo a entender más rápido la estructura de la API.
- Contribuyen a la escalabilidad del sistema en el futuro.
Reglas básicas para crear URI
Ya lo hemos visto, pero vale la pena repetirlo. Así que recuérdalo como un mantra: "Los URI deben ser intuitivos y describir un recurso, no una acción". Esto es lo que significa:
1. Usa sustantivos en lugar de verbos
Los URI deben representar un recurso, no acciones sobre él. Por ejemplo:
- Correcto:
/users(describe el recurso "usuarios"). - Incorrecto:
/getAllUsers(describe una acción).
Ejemplo:
GET /users -> Obtener la lista de todos los usuarios.
GET /users/{id} -> Obtener los datos de un usuario concreto.
POST /users -> Crear un nuevo usuario.
Este enfoque hace que la API sea predecible. La probabilidad de que un desarrollador se equivoque y escriba un URI incorrecto se reduce mucho.
2. Usa plural para colecciones
Cuando desarrollas rutas para colecciones, como la lista de usuarios o la lista de productos, usa el plural. Es una convención aceptada en REST API.
Ejemplo:
/products -> Lista de todos los productos.
/products/{id} -> Producto concreto por ID.
¿Por qué es importante? Porque deja claro que /products es un grupo y /products/{id} es un miembro concreto de ese grupo.
3. Usa anidamiento para representar jerarquía lógica
Si tus recursos tienen dependencia o anidamiento, puedes expresarlo a través de la estructura del URI. Por ejemplo, los pedidos de un usuario se pueden representar así:
GET /users/{userId}/orders -> Obtener todos los pedidos de un usuario.
/users/{userId}/orders/{orderId} -> Obtener un pedido concreto de un usuario.
La estructura anidada ayuda a mostrar la relación entre dos recursos. Por ejemplo, un "pedido" sin usuario puede no tener sentido, pero dentro de /users/{userId} adquiere significado inmediatamente.
4. Consistencia y legibilidad
A menudo en proyectos aparecen URI como este:
/api/v1/get_all_users
Uf... Aquí se rompe todo:
- Uso de underscore en lugar de guion.
- Se indican acciones en lugar de recursos (
get_all_users). - Seguir convenciones implícitas de nomenclatura.
URI bien formado:
/api/v1/users
- Guiones para separar palabras (
-), no underscores (_). - Minimalismo: escribe solo lo que importa.
Los guiones en los URI se perciben mejor y se consideran más legibles.
Trabajo con versiones de la API
El versionado es un aspecto importante de una API flexible. Permite que tu API evolucione sin romper a los clientes antiguos. Normalmente las versiones se incluyen en el URI.
Formas de versionar:
- Versión en la ruta:
Enfoque sencillo y estándar. Conveniente para REST API.
/api/v1/users - Versión en el header: Indicas la versión mediante un header HTTP:
GET /users Content-Type: application/json API-Version: 1 - Versión en un parámetro de consulta:
/users?apiVersion=1
Para simplificar, nosotros normalmente usaremos la versión en la ruta.
Anidamiento y estructuración
Los URI anidados se usan para representar relaciones entre recursos. Pero es importante recordar que el anidamiento excesivo complica el mantenimiento. Una anidación de más de tres niveles ya se considera signo de mala arquitectura.
Buen ejemplo:
/users/{userId}/orders/{orderId}
Mal ejemplo:
/companies/{companyId}/departments/{departmentId}/teams/{teamId}/users/{userId}
Si aparece una estructura tan profunda, quizá convenga replantear el modelo de datos. Por ejemplo, añadir un servicio separado para gestionar "usuarios".
¿Dónde usar Query Parameters?
Query Parameters (parámetros de consulta) son útiles si quieres filtrar, ordenar o afinar los datos. Por ejemplo:
GET /products?category=electronics&sort=price_asc&page=2
Distribución de responsabilidades:
- Los URI se usan para identificar recursos.
- Query Parameters — para búsqueda, ordenación o limitación.
Ejemplo: implementándolo en la práctica
Vamos a aplicar todo lo aprendido y crear un REST API para los recursos "Usuarios" y "Pedidos".
REST-controller para usuarios
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
// Obtener todos los usuarios
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
// Obtener un usuario
@GetMapping("/{userId}")
public User getUserById(@PathVariable Long userId) {
return userService.getUserById(userId);
}
// Crear un usuario
@PostMapping
public User createUser(@RequestBody User newUser) {
return userService.createUser(newUser);
}
// Actualizar un usuario
@PutMapping("/{userId}")
public User updateUser(@PathVariable Long userId, @RequestBody User updatedUser) {
return userService.updateUser(userId, updatedUser);
}
// Eliminar un usuario
@DeleteMapping("/{userId}")
public void deleteUser(@PathVariable Long userId) {
userService.deleteUser(userId);
}
}
Manejo de la anidación para pedidos
@RestController
@RequestMapping("/api/v1/users/{userId}/orders")
public class OrderController {
// Obtener todos los pedidos de un usuario
@GetMapping
public List<Order> getAllOrdersForUser(@PathVariable Long userId) {
return orderService.getOrdersByUserId(userId);
}
// Obtener un pedido concreto
@GetMapping("/{orderId}")
public Order getOrderById(@PathVariable Long userId, @PathVariable Long orderId) {
return orderService.getOrderById(userId, orderId);
}
// Crear un pedido
@PostMapping
public Order createOrder(@PathVariable Long userId, @RequestBody Order newOrder) {
return orderService.createOrderForUser(userId, newOrder);
}
}
Ejemplo de peticiones:
- Obtener todos los usuarios:
GET /api/v1/users - Crear un nuevo usuario:
POST /api/v1/users { "name": "John Doe", "email": "john.doe@example.com" } - Obtener todos los pedidos de un usuario:
GET /api/v1/users/1/orders - Añadir un pedido al usuario:
POST /api/v1/users/1/orders { "product": "Laptop", "quantity": 1 }
Ahora en tu REST API reina el orden y la elegancia. Un diseño pensado de los URI es la clave para la usabilidad y la longevidad de tu API.
GO TO FULL VERSION