API-first approach con Spring Boot e OpenAPI Generator

Quando si sviluppano API, partire subito con il codice può portare a problemi di integrazione, mancanza di documentazione
e refactoring costosi.
In questo articolo vedremo un tipo di approccio differente rispetto a quello tradizionale, chiamato API-first.
Scopriremo insieme come implementare questo approccio utilizzando Spring Boot e OpenAPI Generator.
Approccio Tradizionale vs. approccio API-first
Nell’approccio tradizionale, la scrittura delle API inizia solitamente con l’implementazione del codice, senza una progettazione approfondita di queste ultime.
Questo approccio può rendere le modifiche alle API particolarmente complesse, poiché spesso richiedono interventi significativi sul codice già scritto. Inoltre, i client possono iniziare l’integrazione solo al termine dello sviluppo, rallentando l’intero processo.
L’approccio API-first è una metodologia che pone l’accento sulla progettazione e la definizione delle API come passo precedente alla scrittura del codice. Piuttosto che sviluppare le API come un’attività secondaria o come un’implementazione successiva, l’approccio API-first prevede di definire e progettare le specifiche delle API in modo dettagliato e completo sin dall’inizio, prima di iniziare la fase di implementazione effettiva del software.
I principali vantaggi di questo approccio sono:
- API meglio progettate: dare priorità alla progettazione permette agli sviluppatori di definire API ben documentate, più semplici da mantenere ed evolvere nel tempo.
- Promuove la collaborazione tra i team di sviluppo, analisti e gli stakeholders del progetto favorendo una progettazione condivisa delle API.
- Integrazione più rapida: i consumatori delle API possono iniziare a lavorare subito sulla base della documentazione, senza dover attendere la fine degli sviluppi. Questo è particolarmente vantaggioso in un’architettura a microservizi, dove lo sviluppo parallelo è essenziale.
- Focus sul codice: una volta definita la documentazione OpenAPI, i team possono concentrarsi esclusivamente sull’implementazione del codice.
- Automazione e produttività: grazie a strumenti come OpenAPI Generator, è possibile generare automaticamente classi e interfacce, velocizzando lo sviluppo e mantenendo coerenza tra specifiche e codice.
API-first approach con Spring Boot e OpenAPI Generator
Vediamo come applicare concretamente l’approccio API-first, creando un’API per la risorsa book utilizzando Spring Boot e il plugin OpenAPI Generator. L’unico prerequisito per seguire questo tutorial è avere una JDK versione 21 o superiore installata sul proprio sistema.
Il primo passo è la progettazione dell’API tramite la specifica OpenAPI. Per semplicità, definiamo un’unica operazione:
dato il codice (ISBN) di un libro, l’API restituisce i dettagli del libro, se esiste, oppure un errore con status HTTP 404 in caso contrario.
La prima parte del file openapi.yml
è quindi la seguente:
openapi: 3.0.4
info:
title: Book store
version: 1.0.0
servers:
- url: http://localhost:8080
tags:
- name: book
description: Access to Bookstore
paths:
/books/{isbn}:
get:
tags:
- book
summary: Find book by ISBN.
operationId: findBookByIsbn
parameters:
- name: isbn
in: path
description: The International Standard Book Number (ISBN) of book to return
required: "true"
schema:
type: string
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/BookResponse'
'404':
description: Book not found
content:
application/json:
schema:
$ref: "#/components/schemas/ProblemDetail"
La seconda parte del file openapi.yml contiene gli schema utilizzati dall’unica API progettata, BookResponse e ProblemDetail.
Per semplicità, la risorsa libro (schema BookResponse) è composta dai campi:
- ISBN: rappresenta il codice del libro
- name: rappresenta il nome del libro
- author: nome e cognome dell’autore del libro
- pagesNumber: numero di pagine del libro (campo opzionale)
Lo schema ProblemDetail
è un contenitore di campi standard che descrivono un errore e rappresenta la specifica
dell’RFC 9457 :
components:
schemas:
BookResponse:
type: object
required:
- isbn
- name
properties:
isbn:
type: string
example: 978-9365898088
name:
type: string
example: Spring Boot 3 API Mastery
author:
type: string
example: Vincenzo Racca
pagesNumber:
type: integer
format: int32
example: 330
ProblemDetail:
type: object
properties:
type:
type: string
format: uri
title:
type: string
status:
type: integer
format: int32
detail:
type: string
Una volta progettata l’API, possiamo condividere la specifica OpenAPI con i client e il team di QA, consentendo loro di testare l’integrazione già nelle fasi iniziali utilizzando dei mock.
Nel frattempo, possiamo iniziare l’implementazione dell’API in Java con Spring Boot. Per generare la struttura di base del progetto, ci affidiamo a Spring Initializr,
uno strumento che consente di creare rapidamente lo scheletro di un’applicazione Spring Boot. È possibile utilizzarlo tramite interfaccia grafica o
tramite le sue API: in questo esempio, seguiremo il secondo approccio. Apriamo un terminale ed eseguiamo la seguente chiamata con cURL
:
curl https://start.spring.io/starter.zip -d groupId=com.example -d artifactId=api-first \
-d name=api-first -d packageName=com.example.apifirst \
-d dependencies=web,validation -d javaVersion=21 -d bootVersion=3.4.4 \
-d type=maven-project -o api-first.zip
Il comando permette di scaricare uno zip contenente lo scheletro di un progetto Spring Boot con le dipendenze di:
- Spring MVC: modulo utilizzato per creare API REST
- Validation: modulo che contiene le annotazioni Java di validazione, che mappano i campi di validazione del file OpenAPI, come il campo required
Scompattimao lo zip e apriamo il progetto con un IDE a piacere. Creiamo, nella root del progetto, la cartella openapi e incolliamo il file
openapi.yml
creato precedentemente.
A questo punto, possiamo configurare il plugin OpenAPI Generator, che si occuperà di leggere la specifica OpenAPI e generare automaticamente le
classi necessarie per utilizzare l’API. Per farlo, aggiungiamo il plugin all’interno della sezione plugins
del file pom.xml
:
<build>
<plugins>
...
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.4.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>
${project.basedir}/docs/openapi.yml
</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>com.example.apifirst.generated.api</apiPackage>
<modelPackage>com.example.apifirst.generated.model</modelPackage>
<schemaMappings>
ProblemDetail=org.springframework.http.ProblemDetail
</schemaMappings>
<configOptions>
<interfaceOnly>true</interfaceOnly>
<delegatePattern>true</delegatePattern>
<useSpringBoot3>true</useSpringBoot3>
<openApiNullable>false</openApiNullable>
<useTags>true</useTags>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Con questa configurazione, andiamo a specificare:
- Il file OpenAPI da leggere.
- I package delle classi autogenerate.
- La non generazione della classe ProblemDetail in quanto già Spring ne fornisce una.
- L’utilizzo della versione 3 di Spring Boot.
- La generazione delle sole interfacce REST, lasciando allo sviluppatore il compito di implementarle secondo la logica applicativa.
Siccome il plugin di OpenAPI Generator utilizza le annotazioni di Swagger, abbiamo bisogno di importare la dipendenza di Swagger Annotations:
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.28</version>
</dependency>
Possiamo autogenerare le classi aprendo un terminale e utilizzando il comando ./mvnw clean compile
.
Nella cartella target troveremo le classi autogenerate, in questa struttura:
target
├── classes
│ ├── application.properties
│ └── com
│ └── example
│ └── apifirst
│ ├── ApiFirstApplication.class
│ └── generated
│ ├── api
│ │ ├── ApiUtil.class
│ │ └── BookApi.class
│ └── model
│ └── BookResponse.class
L’interfaccia BookApi contiene i metodi che gestiscono le richieste e le risposte HTTP delle API della risorsa libro. Non dobbiamo far altro che creare una classe Controller che implementi quell’interfaccia. Creiamo il package api e scriviamo la classe BookController:
package com.example.apifirst.api;
import com.example.apifirst.generated.api.BookApi;
import com.example.apifirst.generated.model.BookResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BookController implements BookApi {
@Override
public ResponseEntity<BookResponse> findBookByIsbn(String isbn) {
return ResponseEntity.ok(
new BookResponse()
.isbn(isbn)
.name("Spring Boot 3 API Mastery")
.author("Vincenzo Racca")
.pagesNumber(330)
);
}
}
Per semplicità, ad ogni richiesta della API findBookByIsbn, restituiamo sempre lo stesso risultato. Come puoi notare, il metodo non contiene le solite annotazioni di Spring MVC in quanto queste ultime sono definite nell’interfaccia. Con questo approccio, lo sviluppatore deve preoccuparsi solo della logica dell’API!
Avviamo l’applicazione, aprendo dalla root del progetto un terminale e utilizzando il comando ./mvnw spring-boot:run
.
Dopodiché proviamo l’API col seguente comando:
curl http://localhost:8080/books/978-9365898088
Vedremo la seguente response:
{
"isbn":"978-9365898088",
"name":"Spring Boot 3 API Mastery",
"author":"Vincenzo Racca",
"pagesNumber":330
}
Complimenti! Hai appena creato una API con Spring Boot seguendo l’approccio API-first. Questo metodo ti permette di progettare le API in modo chiaro e strutturato prima di iniziare a scrivere il codice. Il vantaggio? I client possono iniziare a lavorare fin da subito sull’integrazione e tu potrai concentrarti sullo sviluppo, evitando modifiche e continui refactoring.
Se vuoi approfondire questo argomento e migliorare la progettazione di API con Spring Boot, non solo REST ma anche gRPC e GraphQL, puoi acquistare il mio libro Spring Boot 3 API Mastery, disponibile su Amazon: https://amzn.to/4hzAwV1.
Post correlati
- Integrazione di GitHub CodeQL e Checkov per la Sicurezza Completa: Un Approccio Pratico con GitHub Actions
- Scopri i Principi SOLID: Fondamenti per uno Sviluppo con Swift Efficiente
- Ricerca semantica con Ollama
- Professione Accessibility Expert
- Accessibilità e regolamentazioni: tra Accessibility Act e Dichiarazione di Accessibilità