Configurando o Swagger 2 com uma API REST do Spring
1. Visão geral
Ao criar uma API REST, uma boa documentação é fundamental.
Além disso, todas as alterações na API devem ser descritas simultaneamente na documentação de referência. Realizar isso manualmente é um exercício tedioso, portanto a automação do processo era inevitável.
Neste tutorial, examinaremosSwagger 2 for a Spring REST web service. Para este artigo, usaremos a implementaçãoSpringfox da especificação Swagger 2.
Se você não estiver familiarizado com o Swagger, visiteits web page para saber mais antes de continuar com este artigo.
Leitura adicional:
Gere o cliente REST do Spring Boot com Swagger
Saiba como você pode gerar um cliente REST do Spring Boot usando o gerador de código Swagger.
Introdução ao Spring REST Docs
Este artigo apresenta o Spring REST Docs, um mecanismo controlado por teste para gerar documentação para serviços RESTful que é precisa e legível.
2. Projeto Alvo
A criação do serviço REST que usaremos em nossos exemplos não está dentro do escopo deste artigo. Se você já possui um projeto adequado, use-o. Caso contrário, os seguintes links são um bom ponto de partida:
3. Adicionando a Dependência Maven
Como mencionado acima, usaremos a implementação Springfox da especificação Swagger. A versão mais recente pode ser encontradaon Maven Central.
Para adicioná-lo ao nosso projeto Maven, precisamos de uma dependência no arquivopom.xml.
io.springfox
springfox-swagger2
2.9.2
4. Integrando Swagger 2 no projeto
4.1. Configuração Java
A configuração do Swagger gira principalmente em torno do beanDocket.
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
Swagger 2 é habilitado por meio da anotação@EnableSwagger2.
Depois que o beanDocket é definido, seu métodoselect() retorna uma instância deApiSelectorBuilder, que fornece uma maneira de controlar os endpoints expostos pelo Swagger.
Predicados para seleção deRequestHandlers podem ser configurados com a ajuda deRequestHandlerSelectorsePathSelectors. Usarany() para ambos tornará a documentação de toda a sua API disponível por meio do Swagger.
This configuration is enough to integrate Swagger 2 into an existing Spring Boot project. Para outros projetos Spring, alguns ajustes adicionais são necessários.
4.2. Configuração sem Spring Boot
Sem o Spring Boot, você não tem o luxo da configuração automática de seus gerenciadores de recursos. A IU Swagger adiciona um conjunto de recursos que você deve configurar como parte de uma classe que estendeWebMvcConfigurerAdapter, e é anotado com@EnableWebMvc.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
4.3. Verificação
Para verificar se o Springfox está funcionando, você pode visitar o seguinte URL no seu navegador:
O resultado é uma resposta JSON com um grande número de pares de valores-chave, o que não é muito legível por humanos. Felizmente, o Swagger forneceSwagger UI para esse propósito.
5. IU Swagger
A interface do usuário do Swagger é uma solução integrada que facilita muito a interação do usuário com a documentação da API gerada pelo Swagger.
5.1. Habilitando a IU Swagger do Springfox
Para usar a interface do usuário do Swagger, é necessária uma dependência adicional do Maven:
io.springfox
springfox-swagger-ui
2.9.2
Agora você pode testá-lo em seu navegador visitandohttp://localhost:8080/your-app-root/swagger-ui.html
In our case, by the way, the exact URL will be:http://localhost:8080/spring-security-rest/api/swagger-ui.html
O resultado deve ser algo como isto:
5.2. Explorando a documentação do Swagger
Na resposta do Swagger está umlist of all controllers definido em seu aplicativo. Clicar em qualquer um deles listará os métodos HTTP válidos (DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT).
A expansão de cada método fornece dados úteis adicionais, como status de resposta, tipo de conteúdo e uma lista de parâmetros. Também é possível tentar cada método usando a interface do usuário.
A capacidade do Swagger de ser sincronizada com sua base de código é crucial. Para demonstrar isso, você pode adicionar um novo controlador ao seu aplicativo.
@RestController
public class CustomController {
@RequestMapping(value = "/custom", method = RequestMethod.POST)
public String custom() {
return "custom";
}
}
Agora, se você atualizar a documentação do Swagger, verácustom-controller na lista de controladores. Como você sabe, há apenas um método (POST) mostrado na resposta de Swagger.
6. Configuração avançada
O beanDocket do seu aplicativo pode ser configurado para fornecer a você mais controle sobre o processo de geração da documentação da API.
6.1. API de filtragem para resposta de Swagger
Nem sempre é desejável expor a documentação para toda a API. Você pode restringir a resposta de Swagger passando parâmetros para os métodosapis()epaths() da classeDocket.
Como visto acima,RequestHandlerSelectors permite usar os predicadosany ounone, mas também pode ser usado para filtrar a API de acordo com o pacote base, anotação de classe e anotações de método.
PathSelectors fornece filtragem adicional com predicados que verificam os caminhos de solicitação de seu aplicativo. Você pode usarany(),none(),regex() ouant().
No exemplo abaixo, instruiremos o Swagger a incluir apenas controladores de um determinado pacote, com caminhos específicos, usando o predicadoant().
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.example.web.controller"))
.paths(PathSelectors.ant("/foos/*"))
.build();
}
6.2. Informação Personalizada
O Swagger também fornece alguns valores padrão em sua resposta que você pode personalizar, como "Documentação da API", "Criado por e-mail de contato", "Apache 2.0".
Para alterar esses valores, você pode usar o métodoapiInfo(ApiInfo apiInfo). A classeApiInfo que contém informações personalizadas sobre a API.
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller"))
.paths(PathSelectors.ant("/foos/*"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo(
"My REST API",
"Some custom description of API.",
"API TOS",
"Terms of service",
new Contact("John Doe", "www.example.com", "[email protected]"),
"License of API", "API license URL", Collections.emptyList());
}
6.3. Mensagens de resposta de métodos personalizados
Swagger permiteglobally overriding response messages of HTTP methods através do métodoglobalResponseMessage() deDocket. Primeiro, você deve instruir o Swagger a não usar mensagens de resposta padrão.
Suponha que você deseja substituir as mensagens de resposta500e403 para todos os métodosGET. Para conseguir isso, algum código deve ser adicionado ao bloco de inicialização deDocket (o código original foi excluído para maior clareza):
.useDefaultResponseMessages(false)
.globalResponseMessage(RequestMethod.GET,
newArrayList(new ResponseMessageBuilder()
.code(500)
.message("500 message")
.responseModel(new ModelRef("Error"))
.build(),
new ResponseMessageBuilder()
.code(403)
.message("Forbidden!")
.build()));
7. IU Swagger com uma API protegida por OAuth
A IU do Swagger fornece uma série de recursos muito úteis - que abordamos bem até agora. Mas não podemos realmente usar a maioria deles se nossa API estiver protegida e não acessível.
Vamos ver como podemos permitir que Swagger acesse uma API protegida por OAuth - usando o tipo de concessão do Código de Autorização neste exemplo.
Vamos configurar o Swagger para acessar nossa API segura usando o suporteSecuritySchemeeSecurityContext:
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.securitySchemes(Arrays.asList(securityScheme()))
.securityContexts(Arrays.asList(securityContext()));
}
7.1. Configuração de segurança
Definiremos um beanSecurityConfiguration em nossa configuração Swagger - e definiremos alguns padrões:
@Bean
public SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.scopeSeparator(" ")
.useBasicAuthenticationWithAccessCodeGrant(true)
.build();
}
7.2. SecurityScheme
A seguir, definiremos nossoSecurityScheme; isso é usado para descrever como nossa API é protegida (autenticação básica, OAuth2, ...).
Em nosso caso aqui, definiremos um esquema OAuth usado para proteger nossoResource Server:
private SecurityScheme securityScheme() {
GrantType grantType = new AuthorizationCodeGrantBuilder()
.tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/token", "oauthtoken"))
.tokenRequestEndpoint(
new TokenRequestEndpoint(AUTH_SERVER + "/authorize", CLIENT_ID, CLIENT_SECRET))
.build();
SecurityScheme oauth = new OAuthBuilder().name("spring_oauth")
.grantTypes(Arrays.asList(grantType))
.scopes(Arrays.asList(scopes()))
.build();
return oauth;
}
Observe que usamos o tipo de concessão Código de autorização - para o qual precisamos fornecer um ponto de extremidade de token e o URL de autorização do nosso Servidor de autorização OAuth2.
E aqui estão os escopos que precisamos definir:
private AuthorizationScope[] scopes() {
AuthorizationScope[] scopes = {
new AuthorizationScope("read", "for read operations"),
new AuthorizationScope("write", "for write operations"),
new AuthorizationScope("foo", "Access foo API") };
return scopes;
}
Eles são sincronizados com os escopos que realmente definimos em nosso aplicativo, para a API/foos.
7.3. Contexto de Segurança
Por fim, precisamos definir um contexto de segurança para nossa API de exemplo:
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(
Arrays.asList(new SecurityReference("spring_oauth", scopes())))
.forPaths(PathSelectors.regex("/foos.*"))
.build();
}
Observe como o nome que usamos aqui, na referência -spring_oauth - sincroniza com o nome que usamos anteriormente, noSecurityScheme.
7.4. Test
Tudo bem, agora que temos tudo configurado e pronto, vamos dar uma olhada em nossa IU Swagger e tentar acessar a API Foo:
Podemos acessar a interface do usuário do Swagger localmente:
http://localhost:8082/spring-security-oauth-resource/swagger-ui.html
Como podemos ver, agora existe um novo botão "Autorizar" devido às nossas configurações de segurança:
Quando clicamos no botão "Autorizar", podemos ver o seguinte pop-up - para autorizar a interface do usuário do Swagger a acessar a API segura:
Observe que:
-
Já podemos ver CLIENT_ID e CLIENT_SECRET - como já os pré-configuramos (mas ainda podemos alterá-los)
-
Agora podemos selecionar os escopos de que precisamos
Veja como as APIs seguras são marcadas:
E agora, finalmente, podemos acessar nossa API!
Obviamente, é quase desnecessário dizer que precisamos ter cuidado ao expor a interface do usuário do Swagger externamente, agora que essa configuração de segurança está ativa.
8. Conclusão
Neste tutorial, configuramos o Swagger 2 para gerar documentação para uma API REST do Spring. Também exploramos maneiras de visualizar e personalizar a saída do Swagger. E, finalmente, analisamos uma configuração simples do OAuth para o Swagger.
Ofull implementation deste tutorial pode ser encontrado emthe Github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está. Para ver a configuração em um projeto de inicialização, verifiquethis GitHub module.
Para a seção OAuth, o código está disponível em nosso repositóriospring-security-oauth.
E, se você for um alunoof REST With Spring, vá para a Lição 1 do Módulo 7 para um mergulho profundo na configuração do Swagger com Spring e Spring Boot.