Введение в Spring REST Docs

Введение в Spring REST Docs

1. обзор

Spring REST Docs создает документацию для служб RESTful, которая является точной и удобочитаемой. Он сочетает рукописную документацию с автоматически генерируемыми фрагментами документов, созданными с помощью тестов Spring.

2. преимущества

Одной из основных философий, лежащих в основе проекта, является использование тестов для подготовки документации Это гарантирует, что сгенерированная документация всегда точно соответствует фактическому поведению API. Кроме того, вывод готов к обработкеAsciidoctor, набором инструментов публикации, построенным на синтаксисе AsciiDoc. Это тот же инструмент, который используется для создания документации Spring Framework.

Эти подходы уменьшают ограничения, налагаемые другими структурами. Spring REST Docs создает документацию, которая является точной, лаконичной и хорошо структурированной. Затем эта документация позволяет потребителям веб-услуг получать необходимую информацию с минимальными усилиями.

Инструмент имеет ряд других преимуществ, таких как:

  • генерируются фрагменты запросов curl и http

  • легко упаковать документацию в jar-файл проектов

  • легко добавить дополнительную информацию в фрагменты

  • поддерживает как JSON, так и XML

Тесты, которые создают фрагменты, могут быть написаны с использованием либо поддержки Spring MVC Test, Spring Webflux'sWebTestClient, либо REST-Assured.

В наших примерах мы собираемся использовать тесты Spring MVC, но использование других фреймворков очень похоже.

3. зависимости

Идеальный способ начать использовать Spring REST Docs в проекте - это использовать систему управления зависимостями. Здесь мы используем Maven в качестве инструмента сборки, поэтому приведенную ниже зависимость можно скопировать и вставить в ваш POM:


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

Вы также можете проверить Maven Central на наличие новой версии зависимостиhere.

В нашем примере нам нужна зависимостьspring-restdocs-mockmvc, поскольку мы используем поддержку тестов Spring MVC для создания наших тестов.

Если мы хотим писать тесты с использованием WebTestClient или REST Assured, нам потребуются зависимостиspring-restdocs-webtestclient иspring-restdocs-restassured.

4. конфигурация

Как уже упоминалось, мы будем использовать среду Spring MVC Test, чтобы делать запросы к службам REST, которые необходимо документировать. Запуск теста создает фрагменты документации для запроса и полученного ответа.

Мы можем использовать библиотеку с тестами JUnit 4 и JUnit 5. Давайте посмотрим на конфигурацию, необходимую для каждого.

4.1. Конфигурация JUnit 4

Самый первый шаг в создании фрагментов документации для тестов JUnit 4 - этоdeclare a public JUnitRestDocumentation field that is annotated as a JUnit @Rule.

ПравилоJUnitRestDocumentation настроено с выходным каталогом, в который должны быть сохранены сгенерированные сниппеты. Например, этот каталог может быть каталогом сборки Maven:

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

Затем мы настраиваем контекстMockMvc так, чтобы он был настроен для создания документации:

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

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

ОбъектMockMvc настраивается с помощью MockMvcRestDocumentationConfigurer. Экземпляр этого класса можно получить из статического методаdocumentationConfiguration() вorg.springframework.restdocs.mockmvc.MockMvcRestDocumentation.

4.2. Конфигурация JUnit 5

Чтобы работать с тестом JUnit 5, мы должны расширить тест классомRestDocumentationExtension:

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

Этот класс автоматически настраивается с выходным каталогом/target/generated-snippets при использовании Maven или/build/generate-snippets для Gradle.

Затем мы должны настроить экземплярMockMvc в методе@BeforeEach:

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

Если мы не используем JUnit для тестов, мы должны использовать классManualRestDocumentation.

5. RESTful Сервис

Давайте создадим CRUD RESTful-сервис, который мы сможем задокументировать:

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

Затем давайте также добавимIndexController, который возвращает страницу со ссылкой на базовую конечную точкуCRUDController:

@RestController
public class IndexController {

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

6. Тесты JUnit

Вернувшись в тесты, мы можем использовать экземплярMockMvc для вызова наших служб и документирования запроса и ответа.

Во-первых,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();

Такая настройка гарантирует, что для каждого вызоваMockMvc фрагменты по умолчанию создаются в папке с именем тестового метода. Кроме того, применение препроцессораprettyPrint() отображает фрагменты в более удобочитаемом виде.

Давайте продолжим настройку некоторых наших звонков.

Чтобы задокументировать нашу индексную страницу, содержащую ссылку, мы можем использовать статический методlinks():

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

Здесь мы используем методlinkWithRel() для документирования ссылки на/crud.

Чтобы добавить заголовокContent-Type к ответу, мы документируем его с помощью методаheaderWithName() и добавляем его к методуresponseHeaders().

We’re also documenting the response payload using the responseFields() method. Это можно использовать для документирования более сложной части ответа или отдельного поля с помощью методов subsctionWithPath () или fieldWithPath ().

Аналогично ответной нагрузке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"),
        ))));
}

В этом примере мы задокументировали наш POST-запрос, который получает модельCrudInput с полями заголовка и тела и отправляет статус CREATED. Each field is documented using the fieldWithPath() method.

To document request and path parameter, we can use the requestParameters() and pathParameters() methods. Оба метода используют методparameterWithName() для описания каждого параметра:

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

Здесь мы задокументировали нашу конечную точку удаления, которая получает параметр путиid.

Проект Spring REST Docs содержит еще более мощные функции документации, такие как ограничения полей и части запроса, которые можно найти вdocumentation.

7. Выход

После успешного выполнения сборки выходные данные фрагментов документации REST будут сгенерированы и сохранены в папкеtarget/generated-snippets:

Screen Shot 2016-04-04 at 11.48.52 PM

Сгенерированный вывод будет содержать информацию об услуге, о том, как вызвать службу REST, например, вызовы curl, HTTP-запрос и ответ от службы REST, а также ссылки / конечные точки на службу:

Команда CURL

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


HTTP - ответ 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. Использование фрагментов для создания документации

Чтобы использовать фрагменты в более крупном документе, вы можете ссылаться на них с помощью Asciidocincludes.. В нашем случае мы создали документ вsrc/docs с именемapi-guide.adoc:

Screen Shot 2016-05-01 at 8.51.48 PM

В этом документе, если мы хотим сослаться на фрагмент ссылки, мы можем включить его, используя заполнитель{snippets}, который будет заменен Maven при обработке документа:

==== Links

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

9. Плагины Asciidocs Maven

Чтобы преобразовать руководство по API из Asciidoc в читаемый формат, мы можем добавить плагин Maven к жизненному циклу сборки. Есть несколько шагов, чтобы включить это:

  1. Примените плагин Asciidoctor кpom.xml

  2. Добавьте зависимость отspring-restdocs-mockmvc в конфигурациюtestCompile, как указано в разделе зависимостей

  3. Настройте свойство для определения местоположения вывода для сгенерированных фрагментов

  4. Настройте задачуtest для добавления каталога сниппетов в качестве вывода

  5. Настроить задачуasciidoctor

  6. Определите атрибут с именемsnippets, который можно использовать при включении сгенерированных фрагментов в вашу документацию.

  7. Сделайте задачу зависимой от задачиtest, чтобы тесты запускались до создания документации

  8. Настройте каталогsnippets как входной. Все сгенерированные фрагменты будут созданы в этом каталоге

Добавьте каталог сниппетов как свойство вpom.xml, чтобы плагин Asciidoctor мог использовать этот путь для создания сниппетов в этой папке:


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

Конфигурация плагина Maven вpom.xml для генерации фрагментов Asciidoc из сборки выглядит следующим образом:


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

10. Процесс создания документации API

Когда запускается сборка Maven и выполняются тесты, все фрагменты будут созданы в папке фрагментов в настроенном каталогеtarget/generated-snippets. Как только фрагменты сгенерированы, процесс сборки генерирует вывод HTML.

Screen Shot 2016-05-08 at 11.32.25 PM

Сгенерированный файл HTML отформатирован и доступен для чтения, поэтому документация REST готова к использованию. Каждый раз, когда запускается сборка Maven, документы также генерируются с последними обновлениями.

image

11. Заключение

Отсутствие документации лучше, чем неправильная документация, но документы Spring REST помогут создать точную документацию для сервисов RESTful.

Как официальный проект Spring, он достигает своих целей с помощью трех тестовых библиотек: Spring MVC Test,WebTestClient и REST Assured. Этот метод создания документации может помочь в поддержке подхода, основанного на тестировании, для разработки и документирования RESTful API.

Вы можете найти пример проекта, основанный на коде из этой статьи, в папкеlinked GitHub repository.