Acabo de anunciar el nuevo curso Learn Spring , centrado en los fundamentos de Spring 5 y Spring Boot 2:
>> VER EL CURSO1. Información general
Spring REST Docs genera documentación para servicios RESTful que es precisa y legible. Combina documentación escrita a mano con fragmentos de documentos generados automáticamente producidos con pruebas de Spring.
2. Ventajas
Una filosofía importante detrás del proyecto es el uso de pruebas para producir la documentación. Esto garantiza que la documentación generada siempre coincida con precisión con el comportamiento real de la API. Además, la salida está lista para ser procesada por Asciidoctor, una cadena de herramientas de publicación centrada en la sintaxis AsciiDoc. Esta es la misma herramienta que se utiliza para generar la documentación de Spring Framework.
Estos enfoques reducen las limitaciones impuestas por otros marcos. Spring REST Docs produce documentación precisa, concisa y bien estructurada. Esta documentación permite a los consumidores de servicios web obtener la información que necesitan con un mínimo de esfuerzo.
La herramienta tiene otras ventajas, como:
- Se generan fragmentos de solicitud de curl y http
- documentación fácil de empaquetar en archivos jar de proyectos
- fácil de agregar información adicional a los fragmentos
- admite JSON y XML
Las pruebas que producen los fragmentos se pueden escribir utilizando el soporte de Spring MVC Test, WebTestClient de Spring Webflux o REST-Assured.
En nuestros ejemplos, usaremos las pruebas Spring MVC, pero usar los otros marcos es muy similar.
3. Dependencias
La forma ideal de empezar a utilizar Spring REST Docs en un proyecto es mediante un sistema de gestión de dependencias. Aquí, estamos usando Maven como herramienta de compilación, por lo que la siguiente dependencia se puede copiar y pegar en su POM:
org.springframework.restdocs spring-restdocs-mockmvc 2.0.4.RELEASE
También puede consultar Maven Central para obtener una nueva versión de la dependencia aquí.
En nuestro ejemplo, necesitamos la dependencia spring-restdocs-mockmvc ya que estamos usando el soporte de prueba Spring MVC para crear nuestras pruebas.
Si queremos escribir pruebas usando WebTestClient o REST Assured, necesitaremos las dependencias spring-restdocs-webtestclient y spring-restdocs-restassured.
4. Configuración
Como se mencionó, usaremos el marco de prueba Spring MVC para realizar solicitudes a los servicios REST que se documentarán. La ejecución de la prueba produce fragmentos de documentación para la solicitud y la respuesta resultante.
Podemos usar la biblioteca con las pruebas JUnit 4 y JUnit 5. Veamos la configuración necesaria para cada uno.
4.1. Configuración de JUnit 4
El primer paso para generar fragmentos de documentación para las pruebas de JUnit 4 es declarar un campo JUnitRestDocumentation público que está anotado como JUnit @Rule .
La regla JUnitRestDocumentation se configura con el directorio de salida en el que se deben guardar los fragmentos generados. Por ejemplo, este directorio puede ser el directorio de construcción de Maven:
@Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");
A continuación, configuramos el contexto MockMvc para que se configure para producir documentación:
@Autowired private WebApplicationContext context; private MockMvc mockMvc; @Before public void setUp(){ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation)) .build(); }
El objeto MockMvc se configura mediante un MockMvc RestDocumentationConfigurer . Se puede obtener una instancia de esta clase del método estático documentationConfiguration () en org.springframework.restdocs.mockmvc.MockMvcRestDocumentation .
4.2. Configuración de JUnit 5
Para trabajar con una prueba JUnit 5, tenemos que extender la prueba con la clase RestDocumentationExtension :
@ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) @SpringBootTest public class ApiDocumentationJUnit5IntegrationTest { //... }
Esta clase se configura automáticamente con un directorio de salida / target / generate-snippets cuando se usa Maven o / build / generate-snippets para Gradle.
A continuación, tenemos que configurar la instancia de MockMvc en un método @BeforeEach :
@BeforeEach public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) { this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .apply(documentationConfiguration(restDocumentation)).build(); }
Si no estamos usando JUnit para las pruebas, entonces tenemos que usar la clase ManualRestDocumentation .
5. Servicio RESTful
Creemos un servicio CRUD RESTful que podamos documentar:
@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 } }
Luego, agreguemos también un IndexController que devuelve una página con un enlace al punto final base de 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. Pruebas JUnit
De vuelta en las pruebas, podemos usar la instancia de MockMvc para llamar a nuestros servicios y documentar la solicitud y la respuesta.
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:
- Apply the Asciidoctor plugin to the pom.xml
- Add a dependency on spring-restdocs-mockmvc in the testCompile configuration as mentioned in the dependencies section
- Configure a property to define the output location for generated snippets
- Configure the test task to add the snippets directory as an output
- Configure the asciidoctor task
- Define an attribute named snippets that can be used when including the generated snippets in your documentation
- Make the task depend on the test task so that the tests are run before the documentation is created
- 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.
Como proyecto oficial de Spring, logra sus objetivos mediante el uso de tres bibliotecas de prueba: Spring MVC Test, WebTestClient y REST Assured. Este método de generación de documentación puede ayudar a respaldar un enfoque basado en pruebas para desarrollar y documentar API RESTful.
Puede encontrar un proyecto de ejemplo basado en el código de este artículo en el repositorio de GitHub vinculado.
DESCANSO inferior