Introduzione a Spring REST Docs

REST Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Panoramica

Spring REST Docs genera documentazione per i servizi RESTful che è sia accurata che leggibile. Combina documentazione scritta a mano con frammenti di documenti generati automaticamente prodotti con i test di primavera.

2. Vantaggi

Una delle principali filosofie alla base del progetto è l'uso di test per produrre la documentazione. Ciò garantisce che la documentazione generata corrisponda sempre accuratamente al comportamento effettivo dell'API. Inoltre, l'output è pronto per essere elaborato da Asciidoctor, una toolchain di pubblicazione incentrata sulla sintassi di AsciiDoc. Questo è lo stesso strumento utilizzato per generare la documentazione di Spring Framework.

Questi approcci riducono i limiti imposti da altri framework. Spring REST Docs produce documentazione accurata, concisa e ben strutturata. Questa documentazione consente quindi agli utenti del servizio Web di ottenere le informazioni di cui hanno bisogno con il minimo sforzo.

Lo strumento ha alcuni altri vantaggi, come ad esempio:

  • vengono generati i frammenti di richiesta curl e http
  • documentazione facile da inserire nel file jar dei progetti
  • facile aggiungere ulteriori informazioni agli snippet
  • supporta sia JSON che XML

I test che producono gli snippet possono essere scritti utilizzando il supporto Spring MVC Test, WebTestClient di Spring Webflux o REST-Assured.

Nei nostri esempi, utilizzeremo i test Spring MVC, ma l'utilizzo degli altri framework è molto simile.

3. Dipendenze

Il modo ideale per iniziare a utilizzare Spring REST Docs in un progetto è utilizzare un sistema di gestione delle dipendenze. Qui stiamo usando Maven come strumento di compilazione, quindi la dipendenza di seguito può essere copiata e incollata nel tuo POM:

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

Puoi anche controllare Maven Central per una nuova versione della dipendenza qui.

Nel nostro esempio, abbiamo bisogno della dipendenza spring-restdocs-mockmvc poiché stiamo usando il supporto del test Spring MVC per creare i nostri test.

Se vogliamo scrivere test utilizzando WebTestClient o REST Assured, avremo bisogno delle dipendenze spring-restdocs-webtestclient e spring-restdocs-restassured.

4. Configurazione

Come accennato, utilizzeremo il framework Spring MVC Test per effettuare richieste ai servizi REST che devono essere documentati. L'esecuzione del test produce frammenti di documentazione per la richiesta e la risposta risultante.

Possiamo usare la libreria con entrambi i test JUnit 4 e JUnit 5. Vediamo la configurazione necessaria per ciascuno.

4.1. Configurazione JUnit 4

Il primo passo nella generazione di frammenti di documentazione per i test JUnit 4 è dichiarare un campo JUnitRestDocumentation pubblico annotato come @Rule JUnit .

La regola JUnitRestDocumentation viene configurata con la directory di output in cui devono essere salvati gli snippet generati. Ad esempio, questa directory può essere la directory di compilazione di Maven:

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

Successivamente, impostiamo il contesto MockMvc in modo che venga configurato per produrre documentazione:

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

L' oggetto MockMvc viene configurato utilizzando un RestDocumentationConfigurer MockMvc . Un'istanza di questa classe può essere ottenuta dal metodo static documentationConfiguration () su org.springframework.restdocs.mockmvc.MockMvcRestDocumentation .

4.2. Configurazione JUnit 5

Per lavorare con un test JUnit 5, dobbiamo estendere il test con la classe RestDocumentationExtension :

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

Questa classe viene configurata automaticamente con una directory di output / target / generated-snippets quando si utilizza Maven o / build / generate-snippets per Gradle.

Successivamente, dobbiamo configurare l' istanza MockMvc in un metodo @BeforeEach :

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

Se non stiamo usando JUnit per i test, allora dobbiamo usare la classe ManualRestDocumentation .

5. Servizio RESTful

Creiamo un servizio RESTful CRUD che possiamo documentare:

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

Quindi, aggiungiamo anche un IndexController che restituisce una pagina con un collegamento all'endpoint di base CRUDController :

@RestController @RequestMapping("/") public class IndexController { static class CustomRepresentationModel extends RepresentationModel { public CustomRepresentationModel(Link initialLink) { super(initialLink); } } @GetMapping public CustomRepresentationModel index() { return new CustomRepresentationModel(linkTo(CRUDController.class).withRel("crud")); } }

6. Test JUnit

Di nuovo nei test, possiamo utilizzare l' istanza MockMvc per chiamare i nostri servizi e documentare la richiesta e la risposta.

First, 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();

This set up ensures that every for every MockMvc call, the default snippets are created in a folder with the test method's name. Also, applying the prettyPrint() pre-processor displays the snippets in a more easily-readable manner.

Let's continue with customizing some of our calls.

To document our index page which contains a link, we can use the static links() method:

@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")))); }

Here, we're using the linkWithRel() method to document a link to /crud.

To add a Content-Type header to the response we're documenting it using the headerWithName() method and adding it to the responseHeaders() method.

We're also documenting the response payload using the responseFields() method. This can be used to document a more complex subsection of the response or a single field using the subsectionWithPath() or fieldWithPath() methods.

Similar to the response payload, 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", "//www.baeldung.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"), )))); }

In this example, we've documented our POST request that receives a CrudInput model with title and body fields and sends a CREATED status. Each field is documented using the fieldWithPath() method.

To document request and path parameter, we can use the requestParameters() and pathParameters() methods. Both methods use a parameterWithName() method to describe each parameter:

@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") ))); }

Here, we've documented our delete endpoint which receives an id path parameter.

The Spring REST Docs project contains even more powerful documentation functionalities, such as field constraints and request parts that can be found in the documentation.

7. Output

Once the build runs successfully, the output of the REST docs snippets will be generated and will be saved to the target/generated-snippets folder:

The generated output will have the information about the service, how to call the REST service like ‘curl' calls, the HTTP request and response from the REST service, and links/endpoints to the service:

CURL Command

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

HTTP – REST Response

[source,http,options="nowrap"] ---- HTTP/1.1 200 OK Content-Type: application/hal+json;charset=UTF-8 Content-Length: 93 { "_links" : { "crud" : { "href" : "//localhost:8080/crud" } } } ----

8. Using Snippets to Create Documentation

To use the snippets in a larger document, you can reference them using Asciidoc includes. In our case, we have created a document in src/docs called api-guide.adoc:

In that document, if we wished to reference the links snippet, we can include it, using a placeholder {snippets} that will be replaced by Maven when it processes the document:

==== Links include::{snippets}/index-example/links.adoc[]

9. Asciidocs Maven Plugins

To convert the API guide from Asciidoc to a readable format, we can add a Maven plugin to the build lifecycle. There are several steps to enable this:

  1. Apply the Asciidoctor plugin to the pom.xml
  2. Add a dependency on spring-restdocs-mockmvc in the testCompile configuration as mentioned in the dependencies section
  3. Configure a property to define the output location for generated snippets
  4. Configure the test task to add the snippets directory as an output
  5. Configure the asciidoctor task
  6. Define an attribute named snippets that can be used when including the generated snippets in your documentation
  7. Make the task depend on the test task so that the tests are run before the documentation is created
  8. Configure the snippets directory as input. All the generated snippets will be created under this directory

Add the snippet directory as a property in pom.xml so the Asciidoctor plugin can use this path to generate the snippets under this folder:

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

The Maven plugin configuration in the pom.xml to generate the Asciidoc snippets from the build is as below:

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

10. API Doc Generation Process

When the Maven build runs and the tests are executed, all the snippets will be generated in the snippets folder under the configured target/generated-snippets directory. Once the snippets are generated, the build process generates HTML output.

The generated HTML file is formatted and readable, so the REST documentation is ready to use. Every time the Maven build runs, the documents also get generated with the latest updates.

11. Conclusion

Having no documentation is better than wrong documentation, but Spring REST docs will help generate accurate documentation for RESTful services.

In quanto progetto Spring ufficiale, raggiunge i suoi obiettivi utilizzando tre librerie di test: Spring MVC Test, WebTestClient e REST Assured. Questo metodo di generazione della documentazione può aiutare a supportare un approccio basato sui test per lo sviluppo e la documentazione delle API RESTful.

Puoi trovare un progetto di esempio basato sul codice in questo articolo nel repository GitHub collegato.

REST fondo

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO