Einführung in Spring REST Docs

REST Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Übersicht

Spring REST Docs generiert eine Dokumentation für RESTful-Services, die sowohl genau als auch lesbar ist. Es kombiniert handgeschriebene Dokumentation mit automatisch generierten Dokumentausschnitten, die mit Spring-Tests erstellt wurden.

2. Vorteile

Eine wichtige Philosophie hinter dem Projekt ist die Verwendung von Tests zur Erstellung der Dokumentation. Dadurch wird sichergestellt, dass die generierte Dokumentation immer genau dem tatsächlichen Verhalten der API entspricht. Darüber hinaus kann die Ausgabe von Asciidoctor verarbeitet werden, einer Publishing-Toolchain, die sich um die AsciiDoc-Syntax dreht. Dies ist das gleiche Tool, das zum Generieren der Spring Framework-Dokumentation verwendet wird.

Diese Ansätze verringern die durch andere Frameworks auferlegten Einschränkungen. Spring REST Docs erstellt eine Dokumentation, die genau, präzise und gut strukturiert ist. Diese Dokumentation ermöglicht es den Webdienstkonsumenten dann, die benötigten Informationen mit minimalem Aufwand abzurufen.

Das Tool bietet einige weitere Vorteile, z.

  • Curl- und http-Anforderungs-Snippets werden generiert
  • einfach zu packende Dokumentation in Projekt-JAR-Datei
  • Einfach, zusätzliche Informationen zu den Snippets hinzuzufügen
  • unterstützt sowohl JSON als auch XML

Die Tests, die die Snippets erzeugen, können entweder mit Spring MVC Test-Unterstützung, Spring Webflux WebTestClient oder REST-Assured geschrieben werden.

In unseren Beispielen werden wir Spring MVC-Tests verwenden, aber die Verwendung der anderen Frameworks ist sehr ähnlich.

3. Abhängigkeiten

Der ideale Weg, um mit der Verwendung von Spring REST Docs in einem Projekt zu beginnen, ist die Verwendung eines Abhängigkeitsverwaltungssystems. Hier verwenden wir Maven als Build-Tool, sodass die folgende Abhängigkeit kopiert und in Ihr POM eingefügt werden kann:

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

Sie können hier auch in Maven Central nach einer neuen Version der Abhängigkeit suchen.

In unserem Beispiel benötigen wir die Abhängigkeit spring-restdocs-mockmvc, da wir die Spring MVC -Testunterstützung verwenden , um unsere Tests zu erstellen.

Wenn wir Tests mit WebTestClient oder REST Assured schreiben möchten, benötigen wir die Abhängigkeiten spring-restdocs-webtestclient und spring-restdocs-restassured.

4. Konfiguration

Wie bereits erwähnt, verwenden wir das Spring MVC Test Framework, um Anforderungen an die zu dokumentierenden REST-Services zu stellen. Durch Ausführen des Tests werden Dokumentationsausschnitte für die Anforderung und die daraus resultierende Antwort erstellt.

Wir können die Bibliothek sowohl mit JUnit 4- als auch mit JUnit 5-Tests verwenden. Sehen wir uns die jeweils erforderliche Konfiguration an.

4.1. JUnit 4-Konfiguration

Der allererste Schritt beim Generieren von Dokumentationsausschnitten für JUnit 4-Tests besteht darin , ein öffentliches JUnitRestDocumentation- Feld zu deklarieren , das als JUnit @Rule mit Anmerkungen versehen ist .

Die JUnitRestDocumentation- Regel wird mit dem Ausgabeverzeichnis konfiguriert, in dem die generierten Snippets gespeichert werden sollen. Dieses Verzeichnis kann beispielsweise das Build-Out-Verzeichnis von Maven sein:

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

Als Nächstes richten wir den MockMvc- Kontext so ein, dass er für die Erstellung der Dokumentation konfiguriert wird:

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

Das MockMvc- Objekt wird mit einem MockMvc RestDocumentationConfigurer konfiguriert . Eine Instanz dieser Klasse kann über die statische Methode documentationDonfiguration () unter org.springframework.restdocs.mockmvc.MockMvcRestDocumentation abgerufen werden .

4.2. JUnit 5-Konfiguration

Um mit einem JUnit 5-Test arbeiten zu können, müssen wir den Test mit der RestDocumentationExtension- Klasse erweitern:

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

Diese Klasse wird bei Verwendung von Maven oder / build / generate-snippets für Gradle automatisch mit einem Ausgabeverzeichnis / target / generate-snippets konfiguriert .

Als Nächstes müssen wir die MockMvc- Instanz in einer @ BeforeEach- Methode einrichten :

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

Wenn wir JUnit nicht für die Tests verwenden, müssen wir die ManualRestDocumentation- Klasse verwenden.

5. RESTful Service

Erstellen wir einen CRUD RESTful-Service, den wir dokumentieren können:

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

Fügen Sie dann auch einen IndexController hinzu , der eine Seite mit einem Link zum CRUDController-Basisendpunkt zurückgibt :

@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. JUnit-Tests

Zurück in den Tests können wir die MockMvc- Instanz verwenden, um unsere Dienste aufzurufen und die Anforderung und Antwort zu dokumentieren.

Erstens, um sicherzustellen , dass jeder MockMvc Anruf ohne weitere Konfiguration automatisch dokumentiert wir verwenden können alwaysDo () Methode :

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

Diese Einrichtung stellt sicher, dass bei jedem MockMvc- Aufruf die Standard-Snippets in einem Ordner mit dem Namen der Testmethode erstellt werden. Wenn Sie den PreProzessor "ettyPrint () " anwenden, werden die Snippets besser lesbar angezeigt.

Fahren wir mit dem Anpassen einiger unserer Anrufe fort.

Um unsere Indexseite zu dokumentieren, die einen Link enthält, können wir die statische links () -Methode verwenden:

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

Hier verwenden wir die linkWithRel () -Methode, um einen Link zu / crud zu dokumentieren .

Um der Antwort einen Content-Type- Header hinzuzufügen, dokumentieren wir ihn mit der headerWithName () -Methode und fügen ihn der responseHeaders () -Methode hinzu.

Wir dokumentieren auch die Antwortnutzdaten mithilfe der responseFields () -Methode. Dies kann verwendet werden, um einen komplexeren Unterabschnitt der Antwort oder ein einzelnes Feld mit den Methoden subsectionWithPath () oder fieldWithPath () zu dokumentieren.

Ähnlich wie bei der Antwortnutzlast können wir auch die Anforderungsnutzlast mit requestPayload () dokumentieren :

@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 diesem Beispiel haben wir unsere POST-Anforderung dokumentiert, die ein CrudInput- Modell mit Titel- und Textfeldern empfängt und den Status CREATED sendet. Jedes Feld wird mit der Methode fieldWithPath () dokumentiert .

Um Anforderungs- und Pfadparameter zu dokumentieren, können wir die Methoden requestParameters () und pathParameters () verwenden. Beide Methoden verwenden eine parameterWithName () -Methode, um jeden Parameter zu beschreiben:

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

Hier haben wir unseren Löschendpunkt dokumentiert, der einen ID- Pfadparameter empfängt .

Das Spring REST Docs-Projekt enthält noch leistungsfähigere Dokumentationsfunktionen, z. B. Feldeinschränkungen und Anforderungsteile, die in der Dokumentation enthalten sind.

7. Ausgabe

Sobald der Build erfolgreich ausgeführt wurde, wird die Ausgabe der REST-Dokument-Snippets generiert und im Ordner target / generate-snippets gespeichert :

Die generierte Ausgabe enthält Informationen zum Dienst, zum Aufrufen des REST-Dienstes wie "Curl" -Aufrufe, zur HTTP-Anforderung und -Antwort vom REST-Dienst sowie zu Links / Endpunkten zum Dienst:

CURL-Befehl

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

HTTP - REST-Antwort

[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. Verwenden von Snippets zum Erstellen von Dokumentationen

Um die Snippets in einem größeren Dokument zu verwenden, können Sie sie mithilfe von Asciidoc- Includes referenzieren . In unserem Fall haben wir in src / docs ein Dokument mit dem Namen api-guide.adoc erstellt :

Wenn wir in diesem Dokument auf das Link-Snippet verweisen möchten, können wir es mithilfe eines Platzhalters {Snippets} einfügen, der bei der Verarbeitung des Dokuments durch Maven ersetzt wird:

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

9. Asciidocs Maven Plugins

Um das API-Handbuch von Asciidoc in ein lesbares Format zu konvertieren, können wir dem Build-Lebenszyklus ein Maven-Plugin hinzufügen. Es gibt mehrere Schritte, um dies zu aktivieren:

  1. Wenden Sie das Asciidoctor-Plugin auf die Datei pom.xml an
  2. Fügen Sie in der testCompile- Konfiguration eine Abhängigkeit von spring-restdocs-mockmvc hinzu , wie im Abschnitt Abhängigkeiten angegeben
  3. Konfigurieren Sie eine Eigenschaft, um den Ausgabeort für generierte Snippets zu definieren
  4. Konfigurieren Sie die Testaufgabe so , dass das Snippets-Verzeichnis als Ausgabe hinzugefügt wird
  5. Konfigurieren Sie die Asciidoctor- Aufgabe
  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.

Als offizielles Spring-Projekt erreicht es seine Ziele mithilfe von drei Testbibliotheken: Spring MVC Test, WebTestClient und REST Assured. Diese Methode zum Generieren von Dokumentation kann dabei helfen, einen testgetriebenen Ansatz zum Entwickeln und Dokumentieren von RESTful-APIs zu unterstützen.

Ein Beispielprojekt basierend auf dem Code in diesem Artikel finden Sie im verknüpften GitHub-Repository.

REST unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs