O Swagger é um dos frameworks mais usados para se documentar API’s REST. Ele facilita para que os clientes que consomem nossas API’s saibam quais os parâmetros nossas operações recebem, qual o retorno, o modelo, o media type retornado JSON, XML, CSV, binário etc. Sendo assim os clientes não precisam necessariamente discutir com a equipe de desenvolvimento da API sobre como usá-la. Pode-se dizer que a grosso modo o Swagger se comporta como o velho WSDL das aplicações SOAP. Sendo assim esse framework valoriza e muito nossas aplicações.
Tomando como base o projeto do post anterior vamos adicionar as configurações necessárias para habilitar o Swagger na aplicação. Para isso abra o arquivo pom.xml e adicione as tags destacadas com comentários no código abaixo.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>br.com.erudio</groupid> <artifactid>simple-rest-example-swagger</artifactid> <version>0.0.1-SNAPSHOT</version> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.3.3.RELEASE</version> </parent> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <!-- Adicionando a dependencia do Spring Boot Starter Actuator --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-actuator</artifactid> </dependency> <!-- Adicione as dependências do Swagger API necessárias para gerar a documentação da aplicação--> <dependency> <groupid>com.mangofactory</groupid> <artifactid>swagger-springmvc</artifactid> <version>1.0.0</version> </dependency> <dependency> <groupid>org.ajar</groupid> <artifactid>swagger-spring-mvc-ui</artifactid> <version>0.4</version> </dependency> <dependency> <groupid>org.apache.tomcat.embed</groupid> <artifactid>tomcat-embed-jasper</artifactid> <scope>provided</scope> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build> <repositories> <repository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </repository> <!-- Adicione o repositório do Swagger ao projeto--> <repository> <id>jcenter-release</id> <name>jcenter</name> <url>http://oss.jfrog.org/artifactory/oss-release-local/</url> </repository> </repositories> <pluginrepositories> <pluginrepository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </pluginrepository> </pluginrepositories> </project>
Feito isto precisamos alterar a classe Application para que ela acione o Swagger quando inicializar a aplicação.
package br.com.erudio; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import com.mangofactory.swagger.configuration.SpringSwaggerConfig; import com.mangofactory.swagger.models.dto.ApiInfo; import com.mangofactory.swagger.plugin.EnableSwagger; import com.mangofactory.swagger.plugin.SwaggerSpringMvcPlugin; @Configuration // Define a classe como classe de configuração @EnableAutoConfiguration // Habilita a autoconfiguração @EnableSwagger //Habilita o Swagger @ComponentScan(basePackages = {"br.com.erudio"}) //Escaneia todos os pacotes com o padrão br.com.erudio public class Application { //Injeta uma instancia de SpringSwaggerConfig @Autowired private SpringSwaggerConfig swaggerConfig; public static void main(String[] args) { //Troque esta linha SpringApplication.run(Application.class, args); pela linha abaixo new SpringApplicationBuilder(Application.class).web(true).run(args); } @Bean public SwaggerSpringMvcPlugin groupOnePlugin() { return new SwaggerSpringMvcPlugin(swaggerConfig) //Adiciona as configurações do Swagger ao SwaggerSpringMvcPlugin .apiInfo(apiInfo()) //Adiciona as propriedades de configuração .includePatterns("/person.*?", "/greeting.*?") //Habilita o Swagger para os nossos 2 endpoints .swaggerGroup("admin"); } private ApiInfo apiInfo() { ApiInfo apiInfo = new ApiInfo( //Configurações de contato, licença etc não nescessáriamente precisa ser definida "Swagger With Spring Boot", "This is a simple application to demonstrate how to work with Swagger in Spring Boot project!", "Free to use and mess around", "erudio@gmail.com", "Open Licence", "myemail@gmail.com" ); return apiInfo; } }
Agora que o Swagger já está configurado vamos documentar o endpoint Greeting.
package br.com.erudio.web.controllers; import java.util.concurrent.atomic.AtomicLong; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import com.wordnik.swagger.annotations.Api; import com.wordnik.swagger.annotations.ApiOperation; import br.com.erudio.models.Greeting; @Api(value = "greeting") //Diz ao Swagger que esse é um endpoint e REST deve ser documentado @RestController @RequestMapping("/greeting") public class GreetingController { private static final String template = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); @ApiOperation(value = "Show Greeting Message" ) //Diz ao Swagger que essa operação REST deve ser documentado @ResponseStatus(HttpStatus.OK) @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { return new Greeting(counter.incrementAndGet(), String.format(template, name)); } }
Como se pode ver é extremamente simples documentar a nossa API agora vamos vazer o mesmo com o endpoint Person.
package br.com.erudio.web.controllers; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import com.wordnik.swagger.annotations.Api; import com.wordnik.swagger.annotations.ApiOperation; import br.com.erudio.models.Person; import br.com.erudio.services.PersonService; @Api(value = "person") //Diz ao Swagger que esse é um endpoint e REST deve ser documentado @RestController @RequestMapping("/person/") public class PersonController { @Autowired private PersonService personService; @ApiOperation(value = "Find person by ID" ) //Diz ao Swagger que essa operação REST deve ser documentado @ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/{personId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public Person get(@PathVariable(value = "personId") String personId){ return personService.findById(personId); } @ApiOperation(value = "Find all persons" ) //Diz ao Swagger que essa operação REST deve ser documentado @ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/findAll", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List<person> findAll(){ return personService.findAll(); } @ApiOperation(value = "Create a new person" ) //Diz ao Swagger que essa operação REST deve ser documentado @ResponseStatus(HttpStatus.OK) @RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public Person create(@RequestBody Person person){ return personService.create(person); } @ApiOperation(value = "Update an existing person") //Diz ao Swagger que essa operação REST deve ser documentado @ResponseStatus(HttpStatus.OK) @RequestMapping(method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE) public Person update(@RequestBody Person person){ return personService.update(person); } @ApiOperation(value = "Delete person by ID" ) //Diz ao Swagger que essa operação REST deve ser documentado @ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/{personId}", method = RequestMethod.DELETE) public void delete(@PathVariable(value = "personId") String personId){ personService.delete(personId); } }
Não parece mas já terminamos toda a codificação necessária por adicionar o Swagger à nossa API mais uma vez acesse a classe Application e inicie a aplicação como no post anterior. Após inicializada a aplicação acesse a URL:
localhost:8080/sdoc.jsp
Essa é a URL padrão da documentação e nunca tentei alterá-la. Ao acessá-la você verá algo similar a imagem abaixo documentando cada uma das operações dos nossos endpoints. Bastando clicar sobre cada uma para expandir e ver todos os detalhes da mesma.
Na imagem abaixo podemos ver a documentação da operação findAll. Temos a definição do modelo que ela nos retorna, o tipo de dados que ela retorna no caso JSON, os StatusCode que ela pode retornar, se clicarmos em Try Out o Swagger nos permite testar nossas operações. Ao executarmos esse teste a nossa API nos retornou um array de pessoas, o cabeçalho e o StatusCode 200 OK.
Chegamos com este post ao final da série de posts, práticos, sobre serviços REST. Você pode baixar o código deste post aqui e descompactar o arquivo zip e importar na sua IDE preferida ou clonar usando Git:
git clone https://github.com/leandrocgsi/simple-rest-example-swagger.git
Agora você já consegue dar os primeiros passos na criação de serviços REST, conhece conceitos, teóricos e práticos, básicos para executar esse tipo de tarefa. Sendo assim continue ligado no blog, por que no próximos posts iremos detonar o Rock’n Roll com outras tecnologias. É isso aí bons estudos.
Treinamentos relacionados com este post
Muito bom o tutorial, parabéns!!!
Uma dúvida, os requestes mapping do create e do update estão trocados? para criar seria o RequestMethod.Post e para atualizar o RequestMethod.PUT.
Sim Luciana eu acabei invertendo a informação. Coloquei a mensagem de criação no PUT e a de update no POST.
Parabens pelo trabalho!
Obrigado por acompanhar.