Construcción de APIs profesionales
Cuando una API crece y la usan muchos clientes (frontend, apps móviles, otros servicios), es importante diseñarla de forma profesional.
Las APIs modernas deben tener:
- versionado
- respuestas consistentes
- paginación
- filtrado
- manejo de errores
- documentación clara
1. Versionado de API #
Cuando una API cambia, no podemos romper a los clientes existentes.
Por eso se versiona.
Ejemplo:
1/api/v1/users 2/api/v2/users
2. Ejemplo Controller #
1@RestController 2@RequestMapping("/api/v1/users") 3public class UserController { 4 5 @GetMapping 6 public List<UserDTO> getUsers() { 7 return service.getUsers(); 8 } 9 10}
Si cambiamos la API:
1@RequestMapping("/api/v2/users")
3. Respuestas estándar de API #
En APIs grandes se usa un formato común de respuesta.
Ejemplo:
1{ 2 "success": true, 3 "data": {...}, 4 "message": "User created" 5}
4. Clase de respuesta #
1public class ApiResponse<T> { 2 3 private boolean success; 4 private String message; 5 private T data; 6 7}
5. Ejemplo uso #
1@PostMapping 2public ApiResponse<UserDTO> createUser(@RequestBody CreateUserDTO dto) { 3 4 UserDTO user = service.createUser(dto); 5 6 return new ApiResponse<>(true,"User created", user); 7 8}
6. Manejo profesional de errores #
Error típico:
1{ 2 "timestamp": "...", 3 "status": 500, 4 "error": "Internal Server Error" 5}
Esto no es muy útil.
Mejor:
1{ 2 "success": false, 3 "error": "USER_NOT_FOUND", 4 "message": "User not found" 5}
7. Clase ErrorResponse #
1public class ErrorResponse { 2 3 private String error; 4 private String message; 5 6}
8. GlobalExceptionHandler #
1@RestControllerAdvice 2public class GlobalExceptionHandler { 3 4 @ExceptionHandler(UserNotFoundException.class) 5 public ResponseEntity<ErrorResponse> handle(UserNotFoundException ex) { 6 7 ErrorResponse error = new ErrorResponse( 8 "USER_NOT_FOUND", 9 ex.getMessage() 10 ); 11 12 return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); 13 14 } 15 16}
9. Paginación #
Nunca devolver miles de registros.
Spring Data tiene paginación integrada.
10. Repository #
1public interface UserRepository extends JpaRepository<User,Long> { 2 3}
11. Controller #
1@GetMapping 2public Page<User> getUsers(Pageable pageable) { 3 4 return repository.findAll(pageable); 5 6}
12. Petición #
1/users?page=0&size=10
13. Ordenación #
Podemos ordenar resultados.
Ejemplo:
1/users?sort=name
Orden descendente:
1/users?sort=name,desc
14. Filtros simples #
Podemos filtrar datos.
Ejemplo:
1/users?email=test@email.com
15. Repository #
1List<User> findByEmail(String email);
16. Filtros dinámicos #
Para filtros complejos se usan Specifications.
17. Ejemplo #
1Specification<User> spec = (root, query, cb) -> 2 cb.equal(root.get("email"), email);
Esto permite construir consultas dinámicamente.
18. Documentación con Swagger #
Swagger permite documentar la API automáticamente.
Acceso:
1http://localhost:8080/swagger-ui.html
19. Ejemplo anotación #
1@Operation(summary = "Obtener todos los usuarios") 2@GetMapping 3public List<UserDTO> getUsers() { 4 5}
20. Buen diseño de endpoints #
Incorrecto:
1/getAllUsers 2/createUser 3/deleteUser
Correcto:
1GET /users 2POST /users 3GET /users/{id} 4DELETE /users/{id}
21. Códigos HTTP correctos #
| Código | Significado |
|---|---|
| 200 | OK |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 404 | Not Found |
| 500 | Server Error |
22. Ejemplo completo de API profesional #
Controller:
1@GetMapping("/{id}") 2public ResponseEntity<ApiResponse<UserDTO>> getUser(@PathVariable Long id) { 3 4 UserDTO user = service.getUser(id); 5 6 return ResponseEntity.ok( 7 new ApiResponse<>(true,"User found",user) 8 ); 9 10}
Respuesta:
1{ 2 "success": true, 3 "message": "User found", 4 "data": { 5 "id": 1, 6 "name": "Ana" 7 } 8}
23. Buenas prácticas #
Usar nombres REST claros #
1/users 2/courses 3/orders
Usar DTO #
Nunca devolver entidades directamente.
Manejar errores correctamente #
Centralizar con @RestControllerAdvice.
Documentar APIs #
Usar Swagger.
Resumen del tema
Conceptos clave #
- Versionado de APIs (
/api/v1/): evolución controlada de endpoints para garantizar retrocompatibilidad con clientes web, móviles e integradores externos. - Estandarización de respuestas (
ApiResponse<T>yErrorResponse): contratos de respuesta predecibles con metadatos de éxito/error, mensajes descriptivos y carga útil tipada. - Semántica y convenciones REST: uso de sustantivos en plural (
/users), verbos HTTP correctos (GET, POST, PUT, DELETE) y códigos de estado precisos (200, 201, 400, 401, 404, 500). - Paginación, ordenación y filtrado dinámico: uso de
Pageable,SortySpecification(JPA Criteria API) para consultas complejas y eficientes. - Documentación de contratos interactiva: anotaciones OpenAPI (
@Operation,@ApiResponse,@Tag) sincronizadas con Swagger UI para facilitar el consumo y pruebas.
Qué debes recordar #
Diseña APIs REST profesionales con URIs RESTful semánticas, versionado de rutas, respuestas y errores estandarizados, paginación con filtrado dinámico y documentación OpenAPI.