Swagger è un progetto open source utilizzato per generare la documentazione per microservizi. Fornisce un’interfaccia utente per accedere ai nostri servizi web RESTful tramite browser. Per abilitare Swagger nell’applicazione Spring Boot, è necessario aggiungere le seguenti dipendenze nel pom.xml
<!-- SWAGGER 2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency>h <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
Creare una classe contraddistinta dall’annotazione @ EnableSwagger2:
@Configuration @EnableSwagger2 @Api(value="mioprogetto", tags="controller di test che fa alcune operazioni bla bla") public class SwaggerConfig { /* * URL Swagger: http://localhost:9100/swagger-ui.html * Docs: https://swagger.io/docs/ */ @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo")) .paths(regex("/api/ciao.*")) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("ARTICOLI WEB SERVICE API") .description("Spring Boot REST API per la gestione articoli Prova") .version("1.0.0") .license("Apache License Version 2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0") .contact(new Contact("pinco pallino", "https://dgkdg.it", "pinuccio@gg.it")) .build(); } }
Analizziamo il codice:
@Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo")) .paths(regex("/api/ciao.*")) .build() .apiInfo(apiInfo()); }
Questo metodo specifica qual’é il package, e l’url, in cui si trovano i nostri servizi.
private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("ARTICOLI WEB SERVICE API") .description("Spring Boot REST API per la gestione articoli Prova") .version("1.0.0") .license("Apache License Version 2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0") .contact(new Contact("pinco pallino", "https://dgkdg.it", "pinuccio@gg.it")) .build(); }
La classe ApiInfo contiene le informazioni generali dei nostri servizi.
In cima alla classe c’è l’annotation
@Api(value="mioprogetto", tags="controller di test che fa alcune operazioni bla bla") public class SwaggerConfig {
Che ci fornisce informazioni di massima su cosa fa questo micro servizio. Questa info la vedremo in cima alla nostra documentazione.
Analizziamo ora il controller.
package com.example.demo; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; @RestController @CrossOrigin(origins = "http://localhost:4200") @Api(value = "HelloWorldSpringBootSwagger", tags = "Controller di prova ") @RequestMapping("/api") public class HelloController { @ApiModelProperty(notes = "codice del nostro articolo") private String codice; // ------------------- Ricerca Per Codice ------------------------------------ @ApiOperation(value = "Ricerca articolo per codice", notes = "Restituisce i dati dell'articolo in formato JSON", response = String.class, produces = "application/json") @ApiResponses(value = { @ApiResponse(code = 200, message = "L'articolo cercato è stato trovato!"), @ApiResponse(code = 404, message = "L'articolo cercato NON è stato trovato!"), @ApiResponse(code = 403, message = "Non sei AUTORIZZATO ad accedere alle informazioni"), @ApiResponse(code = 401, message = "Non sei AUTENTICATO") }) @RequestMapping(value = "/ciao", method = RequestMethod.GET, produces = "application/json") public ResponseEntity<String> helloWorld() { System.out.println("****** dentro *******"); return new ResponseEntity<String>("ciao mamma", HttpStatus.OK); } // ------------------- Ricerca Per Codice ------------------------------------ @ApiOperation(value = "Ricerca articolo per codice", notes = "Restituisce i dati dell'articolo in formato JSON", response = String.class, produces = "application/json") @ApiResponses(value = { @ApiResponse(code = 200, message = "L'articolo cercato è stato trovato!"), @ApiResponse(code = 404, message = "L'articolo cercato NON è stato trovato!"), @ApiResponse(code = 403, message = "Non sei AUTORIZZATO ad accedere alle informazioni"), @ApiResponse(code = 401, message = "Non sei AUTENTICATO") }) @RequestMapping(value = "/ciaoDue", method = RequestMethod.GET, produces = "application/json") public ResponseEntity<String> helloWorld(@ApiParam("codice articolo") @PathVariable("codice") String codice) { System.out.println("****** dentro *******"); return new ResponseEntity<String>("ciao mamma", HttpStatus.OK); } }
Su ogni metodo aggiungiamo le seguenti annotation:
// ------------------- Ricerca Per Codice ------------------------------------ @ApiOperation(value = "Ricerca articolo per codice", notes = "Restituisce i dati dell'articolo in formato JSON", response = String.class, produces = "application/json") @ApiResponses(value = { @ApiResponse(code = 200, message = "L'articolo cercato è stato trovato!"), @ApiResponse(code = 404, message = "L'articolo cercato NON è stato trovato!"), @ApiResponse(code = 403, message = "Non sei AUTORIZZATO ad accedere alle informazioni"), @ApiResponse(code = 401, message = "Non sei AUTENTICATO") }) @RequestMapping(value = "/ciao", method = RequestMethod.GET, produces = "application/json") public ResponseEntity<String> helloWorld()
che ci informano su cosa fa l’operazione, e i vari codici di risposta che possiamo ottenere.
Se il metodo ha in ingresso un parametro, lo possiamo documentare con @ApiParam(“codice articolo”)
Esempio
// ------------------- Ricerca Per Codice ------------------------------------ @ApiOperation(value = "Ricerca articolo per codice", notes = "Restituisce i dati dell'articolo in formato JSON", response = String.class, produces = "application/json") @ApiResponses(value = { @ApiResponse(code = 200, message = "L'articolo cercato è stato trovato!"), @ApiResponse(code = 404, message = "L'articolo cercato NON è stato trovato!"), @ApiResponse(code = 403, message = "Non sei AUTORIZZATO ad accedere alle informazioni"), @ApiResponse(code = 401, message = "Non sei AUTENTICATO") }) @RequestMapping(value = "/ciaoDue", method = RequestMethod.GET, produces = "application/json") public ResponseEntity<String> helloWorld(@ApiParam("codice articolo") @PathVariable("codice") String codice) { System.out.println("****** dentro *******"); return new ResponseEntity<String>("ciao mamma", HttpStatus.OK); }
Possiamo anche documentare, oltre ai controlller, anche ad esempio le classi model. Per fare questo usiamo l’annotation @ApiModelProperty
Esempio
public class Articolo { // @Id // @Column(name = "CODICE") @ApiModelProperty(notes = "Codice Articolo") private int codice; public int getCodice() { return codice; } public void setCodice(int codice) { this.codice = codice; } }
Avviamo il servizio e vediamo ora che cosa otterremo con queste annotation.
Dal log notiamo
Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
Questo path (v2/api-docs) è quello che dobbiamo richiamare per ottenere la nostra documentazione in formato json
http://localhost:8080/v2/api-docs
Questo formato, anche se leggibile, non è comodo, ma swagger ci fornisce anche una interfaccia grafica consultabile da browser ad uno specifico indirizzo
http://localhost:8080/swagger-ui.html
Questa è la documentazione generata.
Notiamo che è presente anche l’elenco dei metodi generati
con tutte le info che abbiamo inserito