In questo articolo vedremo come partire da un approccio API-first per sviluppare applicazioni lato backend ovvero come generare codice server utilizzando OpenAPI Generator. Il codice verrà generato per un’applicazione Spring Boot.
In parole povere:
- generi le API da swagger editor e scarichi file yaml
- aggiungi dependency e maven plugin e fai mvn clean compile
- ora mi ha creato dei file in target (model layer e api-controller layer) che sposto togliendoli dalla cartella target alla cartella src/main/java
- succede che ogni volta che pusho o faccio ripartire l’app il plugin mi compila ogni volta i file nel maven e da errore perché dice che già esistono allora bisogna dividere i compiti con i profiles. continua a leggere
- se per caso devo modificare lo yaml non faccio ancora mvn clean compile ma
mvn clean generate-sources -Pnomeprofilo
leggi perché_:
“se sposti le cartelle generate in target in src/main/java poi quando fai i tuoi commit e push su git prende anche quei file e dopo un pò devi fare cambiamenti allo yml e devi ricompilare da zero, ti darà errore file doppi perché ricrea gli stessi file nella cartella default target.
questo è stato fatto dal plugin perché non ci sarebbe bisogno ogni volta di pushare anche i file creati da maven nella cartella target perché tanto chi scarica il tuo codice sul suo eclipse avrà anche lui il plugin maven openapi tools e li ricrea ogni volta MA cosi facendo sei limitato alle versioni del plugin, un domani che swagger o il plugin non sono compatibili per diverse versioni rischi di trovarti nei guai.”
allora aggiungiamo dei profiles nel pom alla sezione plugin e dividiamo i compiti. cosi ogni volta anziché fare tutto il clean compile da capo, facciamo generare solo le sources di un certo pezzo di codice.
- ora che abbiamo i file generati dal plugin openapi che usa il file yml di swagger devi capire che i model sono come le entità e
How to design your API first and how to generate code by using the OpenAPI Generator.
Fonti:
Generate Server Code Using OpenAPI Generator
Passaggi:
- design the OpenAPI specification for your application: ovvero creo un file YAML con Swagger Editor
- creo progetto Spring da Initializr vedi es. configurazione da questo articolo
- importo progetto su IDE es. Eclipse
- nel pom.xml inserisco dependencies + OpenApi Maven Plugin (vedi pom.xml esempio da github di reflectoring.io)
dependency e plugin:
-
design the OpenAPI specification for your application con SWAGGER EDITOR
La prima cosa da fare è progettare la specifica OpenAPI per la tua applicazione. Stai per progettare un’API customer. L’API consente di creare un Customer e di recuperare il Customer in base al suo ID. Un’API reale sarà più elaborata, ma questo è un esempio to
keep it simple.
L’intestazione della specifica OpenAPI contiene alcuni metadata sull’API, come title, version, server in esecuzione sull’API. I tags possono essere utilizzati per raggruppare le risorse, il che ti darà una panoramica più ordinata.
openapi: "3.0.2" info: title: API Customer version: "1.0" servers: - url: https://localhost:8080 tags: - name: Customer description: Customer specific data.
La sezione path contiene le specifiche per le risorse. La prima risorsa che definisci è una per creare un nuovo Cliente, al path /customer il che verrà fatto tramite una POST contenente un JSON body (indicato appunto in requestBody > content). Verrà utilizzato operationIddal generator per creare il nome del metodo per questa risorsa. Per semplicità, qui viene considerata solo una response positiva. Gli schema che si riferiscono al corpo JSON, verranno trattati più avanti in questa sezione.
/customer: post: tags: - Customer summary: Create Customer operationId: createCustomer requestBody: content: application/json: schema: $ref: '#/components/schemas/Customer' responses: '200': description: OK content: 'application/json': schema: $ref: '#/components/schemas/CustomerFullData'
La seconda risorsa ci consentirà di recuperare un Customer. Questa risorsa accetta anche un parametro path {customerId} contenente l’ id del customer da recuperare. Se l’ID non esiste, verrà ritornata una risposta NOT FOUND.
/customer/{customerId}: get: tags: - Customer summary: Retrieve Customer operationId: getCustomer parameters: - name: customerId in: path required: true schema: type: integer format: int64 responses: '200': description: OK content: 'application/json': schema: $ref: '#/components/schemas/CustomerFullData' '404': description: NOT FOUND
Infine, nella sezione dei components, vengono definiti gli schemas utilizzati. Lo schema Customer e lo schema CustomerFullData condividono tutte le properties, ad eccezione dell’ID.
Per una migliore manutenibilità, può essere utilizzata la properties allOf .
components:
schemas:
Customer: type: object properties: firstName: type: string description: First name of the customer lastName: type: string description: Last name of the customer
CustomerFullData: allOf: - $ref: '#/components/schemas/Customer' - type: object properties: customerId: type: integer description: The ID of the customer format: int64 description: Full data of the customer.
Generiamo il codice da API Specification
Generazione di codice da una specifica API
Dopo aver definito un’API, creeremo ora il codice dal documento YAML che possiamo esportare da Swagger.
Ci sono due diversi approcci per generare il codice ma quello da evitare è di utilizzare l’ editor Swagger per generare codice.
Meglio utilizzare il plug-in OpenAPI Maven per generare codice da una build Maven.
Generating Code with the OpenAPI Maven plugin:
-
- La nostra
app
sarà una semplice Spring Boot project che possiamo generare automaticamente da start.spring.io aggiungendo la dipendenza spring web. - focalizziamoci sul file
pom.xml
from thespecification
module, where we configure the OpenAPI Maven plugin: - successivamente facciamo partire il comando
mvn clean compile
e facciamo startare l’app conmvn spring-boot:run
- ATTENZIONE: solo la prima volta dobbiamo fare
mvn clean compile
ma se modifichiamo lo yaml poi basta fare mvnmvn clean generate-sources -Pnomedelprofilo
es-Pcodegen
dove nome del profilo va indicato come profiles vedi foto - se invece vogliamo solo pulire la cartella target facciamo
mvn clean
- ora il plugin ha generato il codice dei nostri Model (modelli, le entities) definiti precedentemente es. User e anche il layer API ovvero Controller annotato con @Controller
- il plugin non genera solo i modelli ma anche gli endpoint che sono quelle interfacce che terminano con Delegate es. UserApiDelegate in questo delegate c’è un metodo default il quale viene chiamato se non implementiamo nulla e restituisce un notimplemented, ma qui dentro troverai anche tutti i metodi GET, POST, DELETE etc che avevamo impostato nello Swagger Editor!
- Ovviamente, il generatore non può generare la nostra business logic per noi, ma genera interfacce come UserApiDelegate per noi da implementare. Infatti qui dentro troverai tutti i metodi che avevamo impostato nello Swagger! La logica di business però (quindi l’override dei metodi) la mettiamo nella classe UserApiDelegateImpl annotato con @Service (vedi business layer) cosi anche se ricompiliamo usando il plugin perché magari nel frattempo abbiamo modificato lo yaml, non ci va a sostituire(piallare) la nostra logica di business 🙂
- il generatore plugin crea anche un’interfaccia UserApi che delega le chiamate a UserApiDelegate
- La nostra
IN CONCLUSIONE:
il plugin ci genera i model e le api (le api sono i nostri controller) questo è un’altro approccio a differenza del tutorial di amigoscode che abbiamo visto in questo articolo
4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.6 com.example games 0.0.1-SNAPSHOT games Demo project for Spring Boot 11 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test javax.validation validation-api 2.0.1.Final org.openapitools jackson-databind-nullable 0.2.1 io.springfox springfox-swagger2 2.9.2 org.springdoc springdoc-openapi-ui 1.6.4 org.springdoc springdoc-openapi-ui 1.6.4 org.springframework.boot spring-boot-maven-plugin org.openapitools openapi-generator-maven-plugin 5.1.0 generate ${project.basedir}/src/main/resources/openapi.yaml spring com.example.games.api com.example.games.model ApiUtil.java true
nuovo swagger 3.0
schemas sono i parametri che serrvono alle API
non sono classi java
una post vedila come una lettera
#LETTERA fuori ci sono i parametri ovveroc’è id che è indirizzo a cui mando la lettera e il contenuto dentro la lettera è il requestBody
SWAGGER: 13/04/2022
GET
query: solo nella get
POST, PUT, DELETE
body: passare e prendere cose come array json e poi dall’altra parte nel java usiamo map chiave valore
swagger gestione risorse identificate con id
pensare per risorse identificate con id
GET OTTIENI la fetch
POST CREA RISORSA
PUT modifichi
da swagger posso generare del codice con librerie
bean di trasporto da swagger jackson
CONVERTE formato in oggetto java
da swagger creo codice json serve portare oggetto dentro java o
implementare business logic: scelgo mossa etc..
arena
i bot si registrano nell’arena
il bot chiamaa post macth su di lui (e mi darà id)
poi chiamo postmatch su di te (e mi darà id)
quando io chiamo
partita a curl:
ti arriva oggetto nel contesto di una risorsa
match id serve e basta
https://reflectoring.io/spring-boot-openapi/
manven strumenti di build quando passi dalle classi scritte in java
a jar in mezzo c0’è maven.
plugin di maven su eclipse prende lo swqagger lo legge e dice c’è un sulla risosrsa match
con la funzione get match annnotata con get
etc etrc
tutti gli artefatti da quell’insieme
pom punto rif trasformazione java in qulcosa che esegue
governa passaggio dal codice java all’artefatto eseguibile (jar,war, ear)
pom > maven metto il plugin
quando lancio:
maven install
compila progetto lo impaccchetta e lo emtte dispnibile sul repository locale.
studiare concetto:
REST > risorsa
cdi cosa abbiamo aprlato
1.
INTERNO OGGETTO MOSSA ()
ha senso nello swagger dire guarda che ogni oggetto ticatcamove avraà interno oggetto match.
perchè a noi serve sapere se questa move è di quel match , quindi ci basta id match
nella business logic
da ongi mossa posso accedere al match corrispondente-
2. POST CONNECT FOUR /matchid/ moves
in post sto facendo mossa
3. a livello api rest i model sotto NON sono delle classi.
NON devo pensare a mappare le classi java.
quindi l’id non sempre mi serve ma lo genero poi nella business logic.
a parte quando /tic-tac-toe/matches/{matchId}/moves perchè glielo chiedo come PATH PARAM {matchId}
*************
CONSUMES sono i parametri (quellao che ricevi) (attraverso body path query)
cosa ricevo lo spiego nei PARAMETERS
invece quando produci è nella response
2 commenti su “API-first development con Swagger+ Spring”