Einführung in Spring REST Docs

Einführung in Spring REST Docs

1. Überblick

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 Frühlingstests erstellt wurden.

2. Vorteile

Eine wichtige Philosophie des Projekts 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 vonAsciidoctor verarbeitet werden, einer Veröffentlichungs-Toolchain, die sich um die AsciiDoc-Syntax dreht. Dies ist das gleiche Tool, mit dem die Spring Framework-Dokumentation erstellt wird.

Diese Ansätze verringern die durch andere Frameworks auferlegten Einschränkungen. Spring REST Docs erstellt eine präzise, ​​übersichtliche und gut strukturierte Dokumentation. Diese Dokumentation ermöglicht es den Web-Service-Verbrauchern, die benötigten Informationen mit einem Minimum an Aufwand abzurufen.

Das Tool hat einige andere Vorteile, wie zum Beispiel:

  • curl- und http-Request-Snippets werden generiert

  • Einfach zu packende Dokumentation in Projekt-JAR-Datei

  • Es ist 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 WebfluxWebTestClient 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 Einstieg in die Verwendung von Spring REST Docs in einem Projekt 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.0.RELEASE

Sie können Maven Central auch auf eine neue Version der Abhängigkeithere überprüfen.

In unserem Beispiel benötigen wir die Abhängigkeit vonspring-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ängigkeitenspring-restdocs-webtestclient undspring-restdocs-restassured.

4. Aufbau

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 Dokumentationsschnipsel 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 Dokumentationsschnipsel für JUnit 4-Tests istdeclare a public JUnitRestDocumentation field that is annotated as a JUnit @Rule.

DieJUnitRestDocumentation-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 Kontext vonMockMvco 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();
}

DasMockMvc-Objekt wird mit einem MockMvcRestDocumentationConfigurer konfiguriert. Eine Instanz dieser Klasse kann mit der statischendocumentationConfiguration()-Methode fürorg.springframework.restdocs.mockmvc.MockMvcRestDocumentation erhalten werden.

4.2. JUnit 5-Konfiguration

Um mit einem JUnit 5-Test arbeiten zu können, müssen wir den Test um die KlasseRestDocumentationExtensionerweitern:

@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 dem Ausgabeverzeichnis/target/generated-snippetskonfiguriert.

Als nächstes müssen wir die Instanz vonMockMvcin einer Methode von@BeforeEacheinrichten:

@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 KlasseManualRestDocumentationverwenden.

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 wir dann auch einIndexControllerhinzu, das eine Seite mit einem Link zum Basisendpunkt vonCRUDControllerzurückgibt:

@RestController
public class IndexController {

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

6. JUnit-Tests

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

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

Diese Einrichtung stellt sicher, dass bei jedem Aufruf vonMockMvcdie Standard-Snippets in einem Ordner mit dem Namen der Testmethode erstellt werden. Durch Anwenden des Vorprozessors vonprettyPrint()werden die Snippets außerdem 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 statischelinks()-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 dielinkWithRel()-Methode, um einen Link zu/crud. zu dokumentieren

Um der Antwort einenContent-Type-Header hinzuzufügen, dokumentieren wir ihn mit derheaderWithName()-Methode und fügen ihn derresponseHeaders()-Methode hinzu.

We’re also documenting the response payload using the responseFields() method. 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 Antwortnutzlastwe 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"),
        ))));
}

In diesem Beispiel haben wir unsere POST-Anforderung dokumentiert, die einCrudInput-Modell mit Titel- und Textfeldern empfängt und den Status CREATED sendet. Each field is documented using the fieldWithPath() method.

To document request and path parameter, we can use the requestParameters() and pathParameters() methods. Beide Methoden verwenden eineparameterWithName()-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 den Pfadparameteridempfängt.

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

7. Ausgabe

Sobald der Build erfolgreich ausgeführt wurde, wird die Ausgabe der REST-Dokumentausschnitte generiert und im Ordnertarget/generated-snippetsgespeichert:

Screen Shot 2016-04-04 at 11.48.52 PM

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

CURL-Befehl:

$ curl 'http://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": "http: // 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 mit Asciidocincludes. referenzieren. In unserem Fall haben wir ein Dokument insrc/docs mit dem Namenapi-guide.adoc erstellt:

Screen Shot 2016-05-01 at 8.51.48 PM

Wenn wir in diesem Dokument auf das Link-Snippet verweisen möchten, können wir es mit einem Platzhalter{snippets} aufnehmen, der bei der Verarbeitung des Dokuments durch Maven ersetzt wird:

==== Links

Unresolved directive in spring-rest-docs.adoc - 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 aufpom.xml an

  2. Fügen Sie in der Konfiguration vontestCompile eine Abhängigkeit vonspring-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 Aufgabetesto, dass das Snippets-Verzeichnis als Ausgabe hinzugefügt wird

  5. Konfigurieren Sie die Aufgabeasciidoctor

  6. Definieren Sie ein Attribut mit dem Namensnippets, das verwendet werden kann, wenn die generierten Snippets in Ihre Dokumentation aufgenommen werden

  7. Stellen Sie die Aufgabe von der Aufgabetestabhängig, damit die Tests ausgeführt werden, bevor die Dokumentation erstellt wird

  8. Konfigurieren Sie das Verzeichnissnippetsals Eingabe. Alle generierten Snippets werden in diesem Verzeichnis erstellt

Fügen Sie das Snippet-Verzeichnis als Eigenschaft inpom.xml hinzu, damit das Asciidoctor-Plugin diesen Pfad verwenden kann, um die Snippets unter diesem Ordner zu generieren:


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

Die Maven-Plugin-Konfiguration inpom.xml zum Generieren der Asciidoc-Snippets aus dem Build lautet wie folgt:


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

10. API-Dokumentgenerierungsprozess

Wenn der Maven-Build ausgeführt und die Tests ausgeführt werden, werden alle Snippets im Snippets-Ordner im konfigurierten Verzeichnistarget/generated-snippetsgeneriert. Sobald die Snippets generiert wurden, generiert der Erstellungsprozess eine HTML-Ausgabe.

Screen Shot 2016-05-08 at 11.32.25 PM

Die generierte HTML-Datei ist formatiert und lesbar, sodass die REST-Dokumentation verwendet werden kann. Jedes Mal, wenn der Maven-Build ausgeführt wird, werden die Dokumente auch mit den neuesten Aktualisierungen generiert.

image

11. Fazit

Keine Dokumentation ist besser als eine falsche Dokumentation, aber mit Spring REST-Dokumenten können Sie eine genaue Dokumentation für RESTful-Services erstellen.

Als offizielles Spring-Projekt erreicht es seine Ziele mithilfe von drei Testbibliotheken: Spring MVC Test,WebTestClient und REST Assured. Diese Methode zur Dokumentationserstellung unterstützt einen testgetriebenen Ansatz zur Entwicklung und Dokumentation von RESTful-APIs.

Ein Beispielprojekt basierend auf dem Code in diesem Artikel finden Sie inlinked GitHub repository.