Introduction aux documents REST Spring

Introduction aux documents REST Spring

1. Vue d'ensemble

Spring REST Docs génère une documentation pour les services RESTful à la fois précise et lisible. Il combine une documentation manuscrite avec des extraits de document générés automatiquement avec des tests Spring.

2. Avantages

Une philosophie majeure derrière le projet est l'utilisation de tests pour produire la documentation. Cela garantit que la documentation toujours générée correspond exactement au comportement réel de l'API. De plus, la sortie est prête à être traitée parAsciidoctor, une chaîne d'outils de publication centrée sur la syntaxe AsciiDoc. C'est le même outil que celui utilisé pour générer la documentation de Spring Framework.

Ces approches réduisent les limitations imposées par d'autres cadres. Spring REST Docs produit une documentation précise, concise et bien structurée. Cette documentation permet ensuite aux utilisateurs de services Web d’obtenir les informations dont ils ont besoin avec un minimum de complications.

L'outil présente d'autres avantages, tels que:

  • des extraits de requête curl et http sont générés

  • facile à intégrer la documentation dans le fichier jar des projets

  • facile d'ajouter des informations supplémentaires aux extraits

  • prend en charge les formats JSON et XML

Les tests qui produisent les extraits peuvent être écrits à l'aide de la prise en charge de Spring MVC Test, desWebTestClient de Spring Webflux ou de REST-Assured.

Dans nos exemples, nous allons utiliser des tests Spring MVC, mais l'utilisation des autres frameworks est très similaire.

3. Les dépendances

Le moyen idéal pour commencer à utiliser les documents Spring REST dans un projet consiste à utiliser un système de gestion des dépendances. Ici, nous utilisons Maven comme outil de création, de sorte que la dépendance ci-dessous peut être copiée et collée dans votre POM:


    org.springframework.restdocs
    spring-restdocs-mockmvc
    2.0.0.RELEASE

Vous pouvez également consulter Maven Central pour une nouvelle version de la dépendancehere.

Dans notre exemple, nous avons besoin de la dépendancespring-restdocs-mockmvc puisque nous utilisons la prise en charge des tests Spring MVC pour créer nos tests.

Si nous voulons écrire des tests en utilisant WebTestClient ou REST Assured, nous aurons besoin des dépendancesspring-restdocs-webtestclient etspring-restdocs-restassured.

4. Configuration

Comme mentionné, nous utiliserons le framework Spring MVC Test pour envoyer des requêtes aux services REST qui doivent être documentées. L'exécution du test produit des extraits de documentation pour la demande et la réponse résultante.

Nous pouvons utiliser la bibliothèque avec les tests JUnit 4 et JUnit 5. Voyons la configuration nécessaire pour chacun.

4.1. Configuration de JUnit 4

La toute première étape de la génération d'extraits de documentation pour les tests JUnit 4 est dedeclare a public JUnitRestDocumentation field that is annotated as a JUnit @Rule.

La règleJUnitRestDocumentation est configurée avec le répertoire de sortie dans lequel les extraits de code générés doivent être enregistrés. Par exemple, ce répertoire peut être le répertoire de compilation de Maven:

@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");

Ensuite, nous configurons le contexteMockMvc afin qu'il soit configuré pour produire de la documentation:

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

@Before
public void setUp(){
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
      .apply(documentationConfiguration(this.restDocumentation))
      .build();
}

L'objetMockMvc est configuré à l'aide d'un MockMvcRestDocumentationConfigurer. Une instance de cette classe peut être obtenue à partir de la méthode statiquedocumentationConfiguration() surorg.springframework.restdocs.mockmvc.MockMvcRestDocumentation.

4.2. Configuration de JUnit 5

Pour travailler avec un test JUnit 5, nous devons étendre le test avec la classeRestDocumentationExtension:

@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
@SpringBootTest
public class ApiDocumentationJUnit5IntegrationTest { //... }

Cette classe est automatiquement configurée avec un répertoire de sortie/target/generated-snippets lors de l'utilisation de Maven, ou/build/generate-snippets pour Gradle.

Ensuite, nous devons configurer l'instanceMockMvc dans une méthode@BeforeEach:

@BeforeEach
public void setUp(WebApplicationContext webApplicationContext,
  RestDocumentationContextProvider restDocumentation) {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
      .apply(documentationConfiguration(restDocumentation)).build();
}

Si nous n’utilisons pas JUnit pour les tests, nous devons utiliser la classeManualRestDocumentation.

5. Service RESTful

Créons un service CRUD RESTful que nous pouvons documenter:

@RestController
@RequestMapping("/crud")
public class CRUDController {

    @GetMapping
    public List read(@RequestBody CrudInput crudInput) {
        List returnList = new ArrayList();
        returnList.add(crudInput);
        return returnList;
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping
    public HttpHeaders save(@RequestBody CrudInput crudInput) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setLocation(
          linkTo(CRUDController.class).slash(crudInput.getTitle()).toUri());
        return httpHeaders;
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable("id") long id) {
        // delete
    }
}

Ensuite, ajoutons également unIndexController qui renvoie une page avec un lien vers le point de terminaison de baseCRUDController:

@RestController
public class IndexController {

    @GetMapping("/")
    public ResourceSupport index() {
        ResourceSupport index = new ResourceSupport();
        index.add(linkTo(CRUDController.class).withRel("crud"));
        return index;
    }
}

6. Tests JUnit

De retour dans les tests, nous pouvons utiliser l'instanceMockMvc pour appeler nos services et documenter la requête et la réponse.

Tout d'abord,to make sure every MockMvc call is automatically documented without any further configuration we can use the alwaysDo() method:

this.mockMvc = MockMvcBuilders
  //...
  .alwaysDo(document("{method-name}",
    preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
  .build();

Cette configuration garantit que pour chaque appelMockMvc, les extraits par défaut sont créés dans un dossier portant le nom de la méthode de test. De plus, l'application du pré-processeurprettyPrint() affiche les extraits de code d'une manière plus lisible.

Continuons avec la personnalisation de certains de nos appels.

Pour documenter notre page d'index qui contient un lien, nous pouvons utiliser la méthode statiquelinks():

@Test
public void indexExample() throws Exception {
    this.mockMvc.perform(get("/")).andExpect(status().isOk())
      .andDo(document("index",
        links(linkWithRel("crud").description("The CRUD resource")),
        responseFields(subsectionWithPath("_links")
          .description("Links to other resources"))
        responseHeaders(headerWithName("Content-Type")
          .description("The Content-Type of the payload"))));
}

Ici, nous utilisons la méthodelinkWithRel() pour documenter un lien vers/crud.

Pour ajouter un en-têteContent-Type à la réponse, nous le documentons en utilisant la méthodeheaderWithName() et en l'ajoutons à la méthoderesponseHeaders().

We’re also documenting the response payload using the responseFields() method. Ceci peut être utilisé pour documenter une sous-section plus complexe de la réponse ou un seul champ en utilisant les méthodes sous-sectionWithPath () ou fieldWithPath ().

Similaire à la charge utile de réponse,we can also document the request payload using requestPayload():

@Test
public void crudCreateExample() throws Exception {
    Map crud = new HashMap<>();
    crud.put("title", "Sample Model");
    crud.put("body", "http://www.example.com/");

    this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON)
      .content(this.objectMapper.writeValueAsString(crud)))
      .andExpect(status().isCreated())
      .andDo(document("create-crud-example",
        requestFields(fieldWithPath("id").description("The id of the input"),
          fieldWithPath("title").description("The title of the input"),
          fieldWithPath("body").description("The body of the input"),
        ))));
}

Dans cet exemple, nous avons documenté notre requête POST qui reçoit un modèleCrudInput avec des champs title et body et envoie un statut CREATED. Each field is documented using the fieldWithPath() method.

To document request and path parameter, we can use the requestParameters() and pathParameters() methods. Les deux méthodes utilisent une méthodeparameterWithName() pour décrire chaque paramètre:

@Test
public void crudDeleteExample() throws Exception {
    this.mockMvc.perform(delete("/crud/{id}", 10)).andExpect(status().isOk())
      .andDo(document("crud-delete-example",
      pathParameters(
        parameterWithName("id").description("The id of the input to delete")
      )));
}

Ici, nous avons documenté notre point de terminaison de suppression qui reçoit un paramètre de cheminid.

Le projet Spring REST Docs contient des fonctionnalités de documentation encore plus puissantes, telles que les contraintes de champ et les parties de requête qui peuvent être trouvées dans lesdocumentation.

7. Sortie

Une fois la construction exécutée avec succès, la sortie des extraits de code REST sera générée et sera enregistrée dans le dossiertarget/generated-snippets:

Screen Shot 2016-04-04 at 11.48.52 PM

La sortie générée contiendra les informations sur le service, la procédure à suivre pour appeler le service REST (appels "curl"), la requête HTTP et la réponse du service REST, ainsi que les liens / points de terminaison vers le service:

Commande CURL

$ curl 'http://localhost:8080/' -i


HTTP - Réponse REST

[source,http,options="nowrap"]

HTTP/1.1 200 OK Content-Type: application/hal+json;charset=UTF-8 Content-Length: 93

{"_links": {"crud": {"href": "http: // localhost: 8080 / crud"}}}


8. Utilisation d'extraits de code pour créer de la documentation

Pour utiliser les extraits dans un document plus volumineux, vous pouvez les référencer en utilisant Asciidocincludes. Dans notre cas, nous avons créé un document ensrc/docs appeléapi-guide.adoc:

Screen Shot 2016-05-01 at 8.51.48 PM

Dans ce document, si nous souhaitons référencer l'extrait de liens, nous pouvons l'inclure, en utilisant un espace réservé{snippets} qui sera remplacé par Maven lors du traitement du document:

==== Links

Unresolved directive in spring-rest-docs.adoc - include::{snippets}/index-example/links.adoc[]

9. Plugins Asciidocs Maven

Pour convertir le guide des API d'Asciidoc en un format lisible, nous pouvons ajouter un plugin Maven au cycle de vie de la génération. Il y a plusieurs étapes pour l'activer:

  1. Appliquer le plugin Asciidoctor auxpom.xml

  2. Ajoutez une dépendance surspring-restdocs-mockmvc dans la configurationtestCompile comme mentionné dans la section dépendances

  3. Configurer une propriété pour définir l'emplacement de sortie pour les extraits générés

  4. Configurez la tâchetest pour ajouter le répertoire d'extraits de code en tant que sortie

  5. Configurer la tâcheasciidoctor

  6. Définissez un attribut nommésnippets qui peut être utilisé lors de l'inclusion des extraits de code générés dans votre documentation

  7. Faire dépendre la tâche de la tâchetest afin que les tests soient exécutés avant la création de la documentation

  8. Configurez le répertoiresnippets comme entrée. Tous les extraits générés seront créés dans ce répertoire.

Ajoutez le répertoire d'extraits de code en tant que propriété danspom.xml afin que le plugin Asciidoctor puisse utiliser ce chemin pour générer les extraits sous ce dossier:


    ${project.build.directory}/generated-snippets

La configuration du plugin Maven dans lespom.xml pour générer les extraits Asciidoc à partir de la construction est la suivante:


    org.asciidoctor
    asciidoctor-maven-plugin
    1.5.6
    
        
            generate-docs
            package
            
                process-asciidoc
            
            
                html
                book
                
                    ${snippetsDirectory}
                
                src/docs/asciidocs
                target/generated-docs
             
     
    

10. Processus de génération de document API

Lorsque la construction de Maven s'exécute et que les tests sont exécutés, tous les extraits de code seront générés dans le dossier des extraits de code sous le répertoire configurétarget/generated-snippets. Une fois les extraits générés, le processus de génération génère une sortie HTML.

Screen Shot 2016-05-08 at 11.32.25 PM

Le fichier HTML généré est formaté et lisible, la documentation REST est donc prête à être utilisée. À chaque exécution de la compilation Maven, les documents sont également générés avec les dernières mises à jour.

image

11. Conclusion

Ne pas avoir de documentation est préférable à une mauvaise documentation, mais la documentation Spring REST vous aidera à générer une documentation précise pour les services RESTful.

En tant que projet Spring officiel, il atteint ses objectifs en utilisant trois bibliothèques de test: Spring MVC Test,WebTestClient et REST Assured. Cette méthode de génération de documentation peut aider à prendre en charge une approche basée sur des tests pour développer et documenter des API RESTful.

Vous pouvez trouver un exemple de projet basé sur le code de cet article dans lelinked GitHub repository.