Configuration de Swagger 2 avec une API Spring REST

Configuration de Swagger 2 avec une API Spring REST

1. Vue d'ensemble

Lors de la création d'une API REST, une bonne documentation est essentielle.

De plus, chaque modification de l'API doit être décrite simultanément dans la documentation de référence. Réaliser cela manuellement est un exercice fastidieux, l'automatisation du processus était donc inévitable.

Dans ce tutoriel, nous examineronsSwagger 2 for a Spring REST web service. Pour cet article, nous utiliserons l'implémentationSpringfox de la spécification Swagger 2.

Si vous n'êtes pas familier avec Swagger, vous devriez visiterits web page pour en savoir plus avant de continuer avec cet article.

Lectures complémentaires:

Générer un client REST Spring Boot avec Swagger

Découvrez comment générer un client REST Spring Boot à l'aide du générateur de code Swagger.

Read more

Introduction aux documents REST Spring

Cet article présente Spring REST Docs, un mécanisme piloté par des tests permettant de générer une documentation des services RESTful à la fois précise et lisible.

Read more

Introduction à Asciidoctor en Java

Apprenez à générer des documents en utilisant AsciiDoctor.

Read more

2. Projet cible

La création du service REST que nous allons utiliser dans nos exemples n'entre pas dans le cadre de cet article. Si vous avez déjà un projet adapté, utilisez-le. Sinon, les liens suivants constituent un bon point de départ:

3. Ajout de la dépendance Maven

Comme mentionné ci-dessus, nous utiliserons l'implémentation Springfox de la spécification Swagger. La dernière version peut être trouvéeon Maven Central.

Pour l'ajouter à notre projet Maven, nous avons besoin d'une dépendance dans le fichierpom.xml.


    io.springfox
    springfox-swagger2
    2.9.2

4. Intégrer Swagger 2 dans le projet

4.1. Configuration Java

La configuration de Swagger est principalement centrée sur le haricotDocket.

@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 est activé via l'annotation@EnableSwagger2.

Une fois le beanDocket défini, sa méthodeselect() renvoie une instance deApiSelectorBuilder, qui fournit un moyen de contrôler les points de terminaison exposés par Swagger.

Les prédicats pour la sélection deRequestHandlers peuvent être configurés à l'aide deRequestHandlerSelectors etPathSelectors. L'utilisation deany() pour les deux rendra la documentation de l'ensemble de votre API disponible via Swagger.

This configuration is enough to integrate Swagger 2 into an existing Spring Boot project. Pour les autres projets Spring, des réglages supplémentaires sont nécessaires.

4.2. Configuration sans Spring Boot

Sans Spring Boot, vous n’avez pas le luxe de configurer automatiquement vos gestionnaires de ressources. Swagger UI ajoute un ensemble de ressources que vous devez configurer dans le cadre d'une classe qui étendWebMvcConfigurerAdapter, et est annotée avec@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. Vérification

Pour vérifier que Springfox fonctionne, vous pouvez visiter l'URL suivante dans votre navigateur:

Le résultat est une réponse JSON avec un grand nombre de paires clé-valeur, ce qui n'est pas très lisible par l'homme. Heureusement, Swagger fournitSwagger UI à cet effet.

5. Interface utilisateur Swagger

Swagger UI est une solution intégrée qui facilite beaucoup l'interaction de l'utilisateur avec la documentation de l'API générée par Swagger.

5.1. Activation de l'interface utilisateur Swagger de Springfox

Pour utiliser l'interface utilisateur Swagger, une dépendance Maven supplémentaire est requise:


    io.springfox
    springfox-swagger-ui
    2.9.2

Vous pouvez maintenant le tester dans votre navigateur en visitanthttp://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

Le résultat devrait ressembler à ceci:

Screenshot_1

5.2. Explorer la documentation Swagger

Dans la réponse de Swagger se trouve unlist of all controllers défini dans votre application. Cliquer sur l'un d'entre eux listera les méthodes HTTP valides (DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT).

Le développement de chaque méthode fournit des données utiles supplémentaires, telles que le statut de la réponse, le type de contenu et une liste de paramètres. Il est également possible d'essayer chaque méthode à l'aide de l'interface utilisateur.

La capacité de Swagger à se synchroniser avec votre base de code est cruciale. Pour illustrer cela, vous pouvez ajouter un nouveau contrôleur à votre application.

@RestController
public class CustomController {

    @RequestMapping(value = "/custom", method = RequestMethod.POST)
    public String custom() {
        return "custom";
    }
}

Maintenant, si vous actualisez la documentation Swagger, vous verrezcustom-controller dans la liste des contrôleurs. Comme vous le savez, il n’existe qu’une seule méthode (POST) dans la réponse de Swagger.

6. Configuration avancée

Le beanDocket de votre application peut être configuré pour vous donner plus de contrôle sur le processus de génération de documentation API.

6.1. API de filtrage pour la réponse de Swagger

Il n'est pas toujours souhaitable d'exposer la documentation de l'ensemble de votre API. Vous pouvez restreindre la réponse de Swagger en passant des paramètres aux méthodesapis() etpaths() de la classeDocket.

Comme vu ci-dessus,RequestHandlerSelectors permet d'utiliser les prédicatsany ounone, mais peut également être utilisé pour filtrer l'API en fonction du package de base, de l'annotation de classe et des annotations de méthode.

PathSelectors fournit un filtrage supplémentaire avec des prédicats qui analysent les chemins de requête de votre application. Vous pouvez utiliserany(),none(),regex() ouant().

Dans l'exemple ci-dessous, nous demanderons à Swagger d'inclure uniquement les contrôleurs d'un package particulier, avec des chemins spécifiques, en utilisant le prédicatant().

@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. Informations personnalisées

Swagger fournit également dans sa réponse certaines valeurs par défaut que vous pouvez personnaliser, telles que «Documentation Api», «Créé par e-mail de contact», «Apache 2.0».

Pour modifier ces valeurs, vous pouvez utiliser la méthodeapiInfo(ApiInfo apiInfo). La classeApiInfo qui contient des informations personnalisées sur l'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. Messages de réponse des méthodes personnalisées

Swagger autoriseglobally overriding response messages of HTTP methods à la méthodeglobalResponseMessage() deDocket. Tout d'abord, vous devez indiquer à Swagger de ne pas utiliser les messages de réponse par défaut.

Supposons que vous souhaitiez remplacer les messages de réponse500 et403 pour toutes les méthodesGET. Pour ce faire, du code doit être ajouté au bloc d’initialisation duDocket (le code d’origine est exclu pour plus de clarté):

.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()));

Screenshot_2

7. Interface utilisateur Swagger avec une API sécurisée OAuth

L'interface utilisateur Swagger fournit un certain nombre de fonctionnalités très utiles - que nous avons bien couvertes jusqu'à présent ici. Mais nous ne pouvons pas vraiment utiliser la plupart de ces derniers si notre API est sécurisée et non accessible.

Voyons comment nous pouvons autoriser Swagger à accéder à une API sécurisée OAuth, en utilisant le type d'autorisation Code d'autorisation dans cet exemple.

Nous allons configurer Swagger pour accéder à notre API sécurisée en utilisant la prise en charge deSecurityScheme etSecurityContext:

@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. Configuration de sécurité

Nous allons définir un beanSecurityConfiguration dans notre configuration Swagger - et définir quelques valeurs par défaut:

@Bean
public SecurityConfiguration security() {
    return SecurityConfigurationBuilder.builder()
        .clientId(CLIENT_ID)
        .clientSecret(CLIENT_SECRET)
        .scopeSeparator(" ")
        .useBasicAuthenticationWithAccessCodeGrant(true)
        .build();
}

7.2. SecurityScheme

Ensuite, nous définirons nosSecurityScheme; ceci est utilisé pour décrire comment notre API est sécurisée (authentification de base, OAuth2,…).

Dans notre cas ici, nous allons définir un schéma OAuth utilisé pour sécuriser nosResource 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;
}

Notez que nous avons utilisé le type d'octroi de code d'autorisation - pour lequel nous devons fournir un noeud final de jeton et l'URL d'autorisation de notre serveur d'autorisation OAuth2.

Et voici les domaines que nous devons avoir définis:

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;
}

Celles-ci se synchronisent avec les portées que nous avons réellement définies dans notre application, pour l'API/foos.

7.3. Contexte de sécurité

Enfin, nous devons définir un contexte de sécurité pour notre exemple d'API:

private SecurityContext securityContext() {
    return SecurityContext.builder()
      .securityReferences(
        Arrays.asList(new SecurityReference("spring_oauth", scopes())))
      .forPaths(PathSelectors.regex("/foos.*"))
      .build();
}

Notez comment le nom que nous avons utilisé ici, dans la référence -spring_oauth - se synchronise avec le nom que nous avons utilisé précédemment, dans lesSecurityScheme.

7.4. Test

Très bien, maintenant que tout est configuré et prêt à l'emploi, jetons un coup d'œil à notre interface utilisateur Swagger et essayons d'accéder à l'API Foo:

Nous pouvons accéder à l'interface utilisateur Swagger localement:

http://localhost:8082/spring-security-oauth-resource/swagger-ui.html

Comme nous pouvons le constater, un nouveau bouton «Autoriser» existe maintenant en raison de nos configurations de sécurité:

image

Lorsque nous cliquons sur le bouton «Autoriser», nous pouvons voir la fenêtre suivante: autoriser notre interface utilisateur Swagger à accéder à l'API sécurisée:

image

Notez que:

  • Nous pouvons déjà voir le CLIENT_ID et le CLIENT_SECRET - car nous les avons préconfigurés précédemment (mais nous pouvons toujours les modifier)

  • Nous pouvons maintenant sélectionner les portées dont nous avons besoin

Voici comment les API sécurisées sont marquées:

image

Et maintenant, enfin, nous pouvons utiliser notre API!

Bien sûr, il va presque sans dire que nous devons faire attention à la manière dont nous exposons l'interface utilisateur Swagger à l'extérieur, maintenant que cette configuration de sécurité est active.

8. Conclusion

Dans ce didacticiel, nous avons configuré Swagger 2 pour générer de la documentation pour une API Spring REST. Nous avons également exploré des moyens de visualiser et de personnaliser la sortie de Swagger. Enfin, nous avons examiné une configuration OAuth simple pour Swagger.

Lesfull implementation de ce didacticiel se trouvent dansthe Github project - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel. Pour voir la configuration dans un projet de démarrage, consultezthis GitHub module.

Pour la section OAuth, le code est disponible dans notre référentielspring-security-oauth.

Et, si vous êtes un étudiantof REST With Spring, passez à la leçon 1 du module 7 pour une plongée approfondie dans la configuration de Swagger avec Spring et Spring Boot.