Filed Report
Spring Boot para crear servicios web: cuando tu API se despierta antes que tú
Spring Boot se ha convertido hace tiempo en ese colega que llega al trabajo antes que nadie, ya ha levantado el servidor, ha ajustado la configuración, ha preparado el registro de logs y te mira con un reproche silencioso mientras tú apenas estás abriendo el IDE. Para la creación de servicios web, es ideal precisamente porque elimina gran parte del trabajo rutinario de infraestructura: menos XML, menos acoplamiento manual de componentes y menos bailes rituales alrededor del contenedor de servlets.
Spring Boot se ha convertido desde hace tiempo en ese colega que llega al trabajo antes que nadie, ya ha levantado el servidor, ha ajustado la configuración, ha preparado el registro de logs y te mira con un reproche silencioso mientras tú todavía estás abriendo el IDE. Para la creación de servicios web, es ideal precisamente porque elimina gran parte del trabajo rutinario de infraestructura: menos XML, menos acoplamiento manual de componentes y menos danzas rituales alrededor del contenedor de servlets.
En el centro del enfoque de Spring Boot se encuentra la idea de convención sobre configuración: si el proyecto parece una aplicación web, se comporta como una aplicación web y tiene la dependencia spring-boot-starter-web, el framework no te interroga con una lámpara en la cara, sino que simplemente inicia un servidor embebido, registra los beans estándar y te permite publicar rápidamente endpoints HTTP.
Por qué Spring Boot es conveniente para los servicios web
La creación clásica de una aplicación web en Java solía recordar al montaje de una estación espacial con un destornillador sacado de una caja de cereales. Había que configurar el contenedor, los descriptores de despliegue, las versiones de las librerías y no olvidar ninguna línea mágica; de lo contrario, todo funcionaba perfectamente hasta el momento de la demostración.
Spring Boot cambia esto mediante varios mecanismos potentes:
- Autoconfiguración: el framework analiza el classpath y crea los ajustes estándar de forma automática.
- Dependencias Starter: en lugar de seleccionar manualmente decenas de librerías, se utilizan conjuntos ya preparados.
- Servidor embebido: Tomcat, Jetty o Undertow se inician junto con la aplicación.
- Actuator: proporciona métricas, comprobaciones de salud (health checks) y endpoints técnicos.
- Configuración externa: los parámetros se extraen fácilmente a
application.ymlo a variables de entorno.
Una dependencia de inicio típica para una API HTTP se ve más o menos así:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Después de esto, la aplicación ya está casi lista para fingir que es un microservicio de clase mundial, incluso si por ahora solo sabe responder "OK".
Estructura básica de la aplicación
Una aplicación mínima de Spring Boot consiste en una clase principal y un controlador. La clase principal se marca con la anotación @SpringBootApplication, que de hecho combina varios mecanismos importantes: configuración, escaneo de componentes y autoconfiguración.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Un controlador para un servicio web sencillo puede verse así:
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public Map<String, String> hello() {
return Map.of("message", "Hola desde Spring Boot");
}
}
En este ejemplo:
@RestControllerindica que los métodos devuelven datos directamente en la respuesta HTTP.@RequestMapping("/api")define la ruta base.@GetMapping("/hello")procesa la solicitud GET.- El
Mapse serializa automáticamente a JSON a través de Jackson.
Y sí, bastan unas pocas líneas para que el servidor empiece a comunicarse en JSON con tanta confianza como si hubiera nacido en un centro de datos.
Creación de una API REST
Spring Boot es especialmente popular para las API REST. El enfoque típico es dividir la responsabilidad entre capas:
- Controller: recibe las solicitudes HTTP.
- Service: contiene la lógica de negocio.
- Repository: trabaja con la base de datos.
Por ejemplo, un servicio de gestión de libros:
@RestController
@RequestMapping("/api/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping
public List<BookDto> findAll() {
return bookService.findAll();
}
@PostMapping
public BookDto create(@RequestBody CreateBookRequest request) {
return bookService.create(request);
}
}
La capa de servicio:
@Service
public class BookService {
public List<BookDto> findAll() {
return List.of(
new BookDto(1L, "Spring en acción"),
new BookDto(2L, "Cómo no romper producción un viernes")
);
}
public BookDto create(CreateBookRequest request) {
return new BookDto(3L, request.title());
}
}
Esta división ayuda a:
- Simplificar las pruebas.
- Aislar la lógica de negocio.
- Evitar que el controlador se convierta en un almacén universal de todo lo que alguna vez pasó por el proyecto.
Validación de solicitudes
Cuando un servicio web empieza a recibir datos del mundo exterior, hay que estar preparado para que el mundo exterior envíe a veces cosas absolutamente mágicas: campos vacíos, precios negativos, fechas de nacimiento en el año 3027 y nombres de 9000 caracteres, como si el usuario se hubiera quedado dormido sobre el teclado.
Spring Boot funciona muy bien con Bean Validation:
public record CreateBookRequest(
@NotBlank String title,
@NotNull @Positive BigDecimal price
) {}
En el controlador:
@PostMapping
public BookDto create(@Valid @RequestBody CreateBookRequest request) {
return bookService.create(request);
}
Si los datos no pasan la validación, el framework devolverá un error 400 Bad Request. Para obtener respuestas más prolijas, conviene añadir un manejo global de excepciones mediante @ControllerAdvice.
Trabajo con la base de datos
Para acceder a la base de datos se suele utilizar Spring Data JPA. Esto permite definir la entidad, el repositorio y realizar operaciones típicas casi sin código repetitivo (boilerplate).
Entidad:
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
protected Book() {}
public Book(String title) {
this.title = title;
}
public Long getId() { return id; }
public String getTitle() { return title; }
}
Repositorio:
public interface BookRepository extends JpaRepository<Book, Long> {
}
Configuración en application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: app
password: secret
jpa:
hibernate:
ddl-auto: update
show-sql: true
Esto permite conectar rápidamente PostgreSQL, H2 u otra base de datos. Lo importante es no usar ddl-auto: update en producción sin pensar, porque el esquema de la base de datos prefiere el respeto, la memoria y un plan de migraciones, en lugar de sorpresas repentinas a las tres de la mañana.
Configuración y perfiles
Spring Boot permite gestionar la configuración de forma flexible a través de:
application.propertiesapplication.yml- Variables de entorno
- Perfiles de entorno (
dev,test,prod)
Ejemplo:
server:
port: 8081
spring:
profiles:
active: dev
Se pueden crear por separado application-dev.yml y application-prod.yml para:
- En
dev, usar una base de datos local. - En
test, usar una base de datos en memoria. - En
prod, usar la configuración real sin improvisaciones del estilo "dejemos temporalmente la contraseña admin/admin".
Para una configuración tipada, es conveniente usar @ConfigurationProperties:
@ConfigurationProperties(prefix = "app")
public record AppProperties(String title, String version) {
}
Manejo de errores
Un servicio web de calidad se distingue no solo porque funciona, sino porque falla con elegancia, de forma predecible y sin agresividad pasiva. En lugar de devolver stack traces caóticos, es mejor retornar un JSON estructurado.
Ejemplo de un manejador global:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Map<String, String> handleNotFound(EntityNotFoundException ex) {
return Map.of("error", ex.getMessage());
}
}
Esto hace que la API sea más comprensible para los clientes y reduce significativamente las situaciones en las que el equipo de frontend mira la respuesta del servidor como arqueólogos ante una tablilla misteriosa de una civilización desconocida.
Pruebas de servicios web
Spring Boot ofrece un excelente soporte para pruebas. Se pueden probar:
- Clases individuales mediante JUnit y Mockito.
- La capa web mediante
@WebMvcTest. - Escenarios de integración mediante
@SpringBootTest.
Ejemplo de una prueba de controlador:
@WebMvcTest(BookController.class)
class BookControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private BookService bookService;
@Test
void shouldReturnBooks() throws Exception {
when(bookService.findAll())
.thenReturn(List.of(new BookDto(1L, "Test Book")));
mockMvc.perform(get("/api/books"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].title").value("Test Book"));
}
}
Este enfoque permite verificar el comportamiento HTTP sin arrancar toda la infraestructura. A su vez, esto salva el sistema nervioso del proceso de construcción (build) y reduce la probabilidad de que una sola prueba tarde más en ejecutarse que un invierno promedio.
Monitoreo y capacidades "production-ready"
Para los servicios web reales, no solo son importantes los controladores, sino también la observabilidad. Aquí entra en juego Spring Boot Actuator.
Dependencia:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Endpoints útiles:
/actuator/health/actuator/info/actuator/metrics/actuator/prometheus
Actuator permite:
- Comprobar el estado del servicio.
- Integrarse con Prometheus y Grafana.
- Ver métricas de la JVM, solicitudes HTTP y pools de conexiones.
A producción le gusta la calma, las métricas y el comportamiento predecible. No le gustan las frases "en mi local funciona" ni "esto es muy raro", especialmente si se pronuncian en la misma llamada.
Ventajas y desafíos comunes
Ventajas
- Inicio rápido del proyecto.
- Mínima configuración manual.
- Integración sencilla con el ecosistema Spring.
- Buen soporte para pruebas.
- Listo para producción gracias a Actuator, logging, perfiles y métricas.
Desafíos
- Exceso de "magia" en la autoconfiguración si no se entiende qué ocurre exactamente.
- Riesgo de crear un monolito "pesado" con cientos de beans.
- Necesidad de controlar el tiempo de arranque y el uso de memoria.
- Dificultad para diagnosticar cuando algo se "configuró solo" de una manera no esperada.
Spring Boot acelera el desarrollo de forma excelente, pero no sustituye el pensamiento arquitectónico. Si se añade todo sin criterio a un solo servicio, tarde o temprano hasta la autoconfiguración más elegante empezará a respirar con dificultad y a mirar al horizonte.
Conclusión
Spring Boot es una de las herramientas más eficaces para crear servicios web en Java. Proporciona un inicio rápido, un modelo de desarrollo cómodo y una integración potente con REST, validación, acceso a datos, pruebas y monitoreo. Para un equipo, esto significa menos tiempo en detalles de infraestructura y más tiempo para crear funcionalidad de negocio.
En resumen, Spring Boot permite construir un servicio web para que luzca serio, funcione de forma estable y no exija del desarrollador una hechicería diaria sobre la configuración. Y en el desarrollo moderno, eso es casi una forma de lujo ingenieril.
Public Response
Comments
No comments yet.