Filed Report
Spring Boot per la creazione di servizi web: quando la tua API si sveglia prima di te
Spring Boot è diventato da tempo quel collega che arriva al lavoro prima di tutti gli altri, ha già avviato il server, impostato la configurazione, preparato i log e ti guarda con silenzioso rimprovero mentre stai ancora aprendo l'IDE. Per la creazione di servizi web è ideale proprio perché rimuove gran parte del lavoro infrastrutturale di routine: meno XML, meno assemblaggio manuale dei componenti, meno danze rituali intorno al servlet container.
Spring Boot è diventato da tempo quel collega che arriva in ufficio prima di tutti, ha già avviato il server, impostato la configurazione, preparato i log e ti guarda con un silenzioso rimprovero mentre stai ancora aprendo l'IDE. Per la creazione di servizi web è ideale proprio perché elimina gran parte del lavoro infrastrutturale di routine: meno XML, meno assemblaggio manuale dei componenti, meno danze rituali attorno al servlet container.
Al centro dell'approccio di Spring Boot risiede l'idea di convention over configuration: se il progetto sembra un'applicazione web, si comporta come un'applicazione web e ha la dipendenza spring-boot-starter-web, il framework non ti sottopone a un interrogatorio con la luce puntata in faccia, ma avvia semplicemente un server embedded, registra i bean standard e ti permette di pubblicare rapidamente endpoint HTTP.
Perché Spring Boot è comodo per i servizi web
Un tempo, la creazione classica di un'applicazione web Java ricordava l'assemblaggio di una stazione spaziale usando un cacciavite trovato in una scatola di cereali. Bisognava configurare il container, i descrittori di deployment, le versioni delle librerie e non dimenticare alcuna riga magica, altrimenti tutto funzionava regolarmente solo fino al momento della demo.
Spring Boot cambia tutto questo grazie ad alcuni meccanismi potenti:
- Autoconfigurazione — il framework analizza il classpath e crea automaticamente le impostazioni predefinite.
- Starter dependencies — al posto della selezione manuale di decine di librerie, si utilizzano set già pronti.
- Embedded server — Tomcat, Jetty o Undertow vengono avviati insieme all'applicazione.
- Actuator — fornisce metriche, health check ed endpoint tecnici.
- Configurazione esterna — i parametri si spostano facilmente in
application.ymlo variabili d'ambiente.
Una tipica dipendenza iniziale per un'API HTTP appare più o meno così:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Dopodiché l'applicazione è quasi pronta a fingere di essere un microservizio di livello mondiale, anche se per ora sa solo rispondere "OK".
Struttura base dell'applicazione
Un'applicazione Spring Boot minima consiste in una classe principale e un controller. La classe principale è contrassegnata dall'annotazione @SpringBootApplication, che di fatto unisce diversi meccanismi importanti: configurazione, scansione dei componenti e autoconfigurazione.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Un controller per un semplice servizio web può apparire così:
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public Map<String, String> hello() {
return Map.of("message", "Saluti da Spring Boot");
}
}
In questo esempio:
@RestControllerindica che i metodi restituiscono i dati direttamente nella risposta HTTP.@RequestMapping("/api")definisce il percorso di base.@GetMapping("/hello")gestisce la richiesta GET.Mapviene serializzata automaticamente in JSON tramite Jackson.
E così, bastano poche righe perché il server inizi a comunicare in JSON con la sicurezza di chi è nato in un data center.
Creazione di REST API
Spring Boot è particolarmente popolare per le REST API. L'approccio tipico è separare le responsabilità tra i layer:
- Controller — riceve le richieste HTTP.
- Service — contiene la logica di business.
- Repository — lavora con il database.
Ad esempio, un servizio di gestione libri:
@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);
}
}
Il layer di servizio:
@Service
public class BookService {
public List<BookDto> findAll() {
return List.of(
new BookDto(1L, "Spring in Action"),
new BookDto(2L, "Come non rompere la prod di venerdì")
);
}
public BookDto create(CreateBookRequest request) {
return new BookDto(3L, request.title());
}
}
Questa separazione aiuta a:
- semplificare i test;
- isolare la logica di business;
- evitare che il controller diventi un magazzino universale di tutto ciò che è passato per il progetto.
Validazione delle richieste
Quando un servizio web inizia a ricevere dati dal mondo esterno, bisogna essere pronti al fatto che il mondo esterno a volte invia cose assolutamente bizzarre: campi vuoti, prezzi negativi, date di nascita nel 3027 e nomi di 9000 caratteri, come se l'utente si fosse addormentato sulla tastiera.
Spring Boot lavora bene con Bean Validation:
public record CreateBookRequest(
@NotBlank String title,
@NotNull @Positive BigDecimal price
) {}
Nel controller:
@PostMapping
public BookDto create(@Valid @RequestBody CreateBookRequest request) {
return bookService.create(request);
}
Se i dati non superano la validazione, il framework restituirà un errore 400 Bad Request. Per risposte più pulite, vale la pena aggiungere una gestione globale delle eccezioni tramite @ControllerAdvice.
Lavorare con il database
Per l'accesso al database si usa spesso Spring Data JPA. Questo permette di descrivere l'entità, il repository ed eseguire operazioni tipiche quasi senza codice boilerplate.
Entità:
@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; }
}
Repository:
public interface BookRepository extends JpaRepository<Book, Long> {
}
Configurazione in application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: app
password: secret
jpa:
hibernate:
ddl-auto: update
show-sql: true
Questo permette di collegare rapidamente PostgreSQL, H2 o un altro database. L'importante è non usare ddl-auto: update in produzione senza riflettere, perché lo schema del database ama il rispetto, la memoria e un piano di migrazione, non le sorprese improvvise alle tre del mattino.
Configurazione e profili
Spring Boot permette di gestire la configurazione in modo flessibile tramite:
application.propertiesapplication.yml- variabili d'ambiente
- profili d'ambiente (
dev,test,prod)
Esempio:
server:
port: 8081
spring:
profiles:
active: dev
Separatamente si possono creare application-dev.yml e application-prod.yml per:
- in dev, usare un database locale;
- in test, usare un DB in-memory;
- in prod, usare la configurazione reale senza improvvisazioni in stile "lasciamo solo temporaneamente la password admin/admin".
Per una configurazione tipizzata è comodo usare @ConfigurationProperties:
@ConfigurationProperties(prefix = "app")
public record AppProperties(String title, String version) {
}
Gestione degli errori
Un servizio web di qualità si distingue non solo perché funziona, ma anche perché sbaglia in modo elegante, prevedibile e senza aggressività passiva. Invece di stack trace caotici nella risposta, è meglio restituire un JSON strutturato.
Esempio di gestore globale:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Map<String, String> handleNotFound(EntityNotFoundException ex) {
return Map.of("error", ex.getMessage());
}
}
Questo rende l'API più comprensibile per i client e riduce significativamente le situazioni in cui il team frontend guarda la risposta del server come archeologi davanti a una misteriosa tavoletta di una civiltà ignota.
Testing dei servizi web
Spring Boot ha un ottimo supporto per il testing. Si possono testare:
- singole classi tramite JUnit e Mockito;
- il livello web tramite
@WebMvcTest; - scenari di integrazione tramite
@SpringBootTest.
Esempio di test del controller:
@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"));
}
}
Questo approccio permette di verificare il comportamento HTTP senza avviare tutta l'infrastruttura. E questo, a sua volta, salva il sistema nervoso della build e riduce la probabilità che un singolo test duri più di un inverno medio.
Monitoraggio e funzionalità production-ready
Per i servizi web reali, non sono importanti solo i controller, ma anche l'osservabilità. Qui entra in gioco Spring Boot Actuator.
Dipendenza:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Endpoint utili:
/actuator/health/actuator/info/actuator/metrics/actuator/prometheus
Actuator offre la possibilità di:
- verificare lo stato del servizio;
- integrarsi con Prometheus e Grafana;
- visualizzare metriche della JVM, richieste HTTP, pool di connessioni.
La produzione ama la calma, le metriche e il comportamento prevedibile. Non ama frasi come "a me in locale funziona" o "è molto strano", specialmente se pronunciate durante la stessa chiamata.
Vantaggi e sfide tipiche
Vantaggi
- avvio rapido del progetto;
- minima configurazione manuale;
- integrazione agevole con l'ecosistema Spring;
- ottimo supporto al testing;
- pronto per la produzione grazie ad Actuator, logging, profili e metriche.
Sfide
- eccessiva "magia" dell'autoconfigurazione, se non si capisce cosa sta succedendo esattamente;
- rischio di creare un monolite "ciccio" con centinaia di bean;
- necessità di controllare i tempi di avvio e l'utilizzo della memoria;
- difficoltà nella diagnosi quando qualcosa "si è configurato da solo" in modo diverso dalle aspettative.
Spring Boot accelera notevolmente lo sviluppo, ma non annulla il pensiero architettonico. Se si mette tutto insieme in un unico servizio senza criterio, prima o poi anche la più elegante autoconfigurazione inizierà a respirare a fatica e a guardare lontano.
Conclusione
Spring Boot è uno degli strumenti più efficaci per creare servizi web in Java. Offre un avvio rapido, un modello di sviluppo comodo e una potente integrazione con REST, validazione, accesso ai dati, testing e monitoraggio. Per un team, questo significa meno tempo dedicato ai dettagli infrastrutturali e più tempo per la creazione di funzionalità di business.
In breve, Spring Boot permette di costruire un servizio web in modo che appaia serio, funzioni stabilmente e non richieda allo sviluppatore una stregoneria quotidiana sulla configurazione. E nello sviluppo moderno, questa è già quasi una forma di lusso ingegneristico.
Public Response
Comments
No comments yet.