Перейти к основному содержимому

Документирование Spring REST API с использованием OpenAPI 3.0

· 8 мин. чтения

1. Обзор

Документация является неотъемлемой частью создания REST API. В этом руководстве мы рассмотрим SpringDoc — инструмент, который упрощает создание и обслуживание документации по API на основе спецификации OpenAPI 3 для приложений Spring Boot 1.x и 2.x.

2. Настройка springdoc-openapi

Чтобы springdoc-openapi автоматически генерировал документы спецификации OpenAPI 3 для нашего API, мы просто добавляем зависимость springdoc-openapi-ui в наш pom.xml :

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>

Затем, когда мы запустим наше приложение, описания OpenAPI по умолчанию будут доступны по пути /v3/api-docs :

http://localhost:8080/v3/api-docs/

Чтобы использовать собственный путь, мы можем указать в файле application.properties :

springdoc.api-docs.path=/api-docs

Теперь мы сможем получить доступ к документам по адресу:

http://localhost:8080/api-docs/

Определения OpenAPI `по умолчанию имеют формат JSON. Для формата yaml` мы можем получить определения по адресу:

http://localhost:8080/api-docs.yaml

3. Настройка springdoc-openapi с пользовательским интерфейсом Swagger

Помимо создания самой спецификации OpenAPI 3, мы можем интегрировать springdoc-openapi с пользовательским интерфейсом Swagger, чтобы мы могли взаимодействовать с нашей спецификацией API и использовать конечные точки.

3.1. Зависимость от Maven

Все, что нам нужно сделать, чтобы настроить springdoc-openapi с пользовательским интерфейсом Swagger, — это добавить зависимость springdoc-openapi-ui в pom.xml проекта :

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>

Теперь мы можем получить доступ к документации API по адресу:

http://localhost:8080/swagger-ui.html

3.2. Поддержка свойств swagger-ui

Springdoc-openapi также поддерживает свойства swagger -ui . Их можно использовать как свойства Spring Boot с префиксом springdoc.swagger-ui .

Например, давайте настроим путь к нашей документации по API. Мы можем сделать это, изменив наш application.properties , включив в него:

springdoc.swagger-ui.path=/swagger-ui-custom.html

Итак, теперь наша документация по API будет доступна по адресу http://localhost:8080/swagger-ui-custom.html .

В качестве другого примера, чтобы отсортировать пути API в порядке их HTTP-методов, мы можем добавить:

springdoc.swagger-ui.operationsSorter=method

3.3. Пример API

Предположим, что в нашем приложении есть контроллер для управления Books :

@RestController
@RequestMapping("/api/book")
public class BookController {

@Autowired
private BookRepository repository;

@GetMapping("/{id}")
public Book findById(@PathVariable long id) {
return repository.findById(id)
.orElseThrow(() -> new BookNotFoundException());
}

@GetMapping("/")
public Collection<Book> findBooks() {
return repository.getBooks();
}

@PutMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public Book updateBook(
@PathVariable("id") final String id, @RequestBody final Book book) {
return book;
}
}

Затем, когда мы запускаем наше приложение, мы можем просмотреть документацию по адресу:

http://localhost:8080/swagger-ui-custom.html

./80fa5d59461e21de0d6c1dda4a92b418.png

Давайте перейдем к конечной точке /api/book и посмотрим подробности ее запроса и ответа:

./26dc82e2ddd35756692fb5cfa5ee9de6.png

4. Интеграция springdoc-openapi с Spring WebFlux

Мы можем интегрировать springdoc-openapi и пользовательский интерфейс Swagger в проект Spring WebFlux, добавив springdoc-openapi-webflux-ui :

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.6.4</version>
</dependency>

Как и прежде, документы будут доступны по адресу:

http://localhost:8080/swagger-ui.html

Чтобы настроить путь, мы могли бы снова добавить свойство springdoc.swagger-ui.path в наш application.properties .

5. Разоблачение информации о разбиении на страницы

Spring Data JPA легко интегрируется с Spring MVC. Одним из примеров такой интеграции является поддержка Pageable :

@GetMapping("/filter")
public Page<Book> filterBooks(@ParameterObject Pageable pageable) {
return repository.getBooks(pageable);
}

Сначала мы могли бы ожидать, что SpringDoc добавит параметры запроса страницы , размера и сортировки в сгенерированную документацию. Однако по умолчанию SpringDoc не соответствует этому ожиданию. Чтобы разблокировать эту функцию, мы должны добавить зависимость springdoc-openapi-data-rest :

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-data-rest</artifactId>
<version>1.6.4</version>
</dependency>

Теперь он добавляет в документацию ожидаемые параметры запроса:

./0080f9ae22e52478a661a89b66dc0810.png

6. Использование плагина Springdoc-openapi Maven

Библиотека springdoc-openapi предоставляет подключаемый модуль Maven springdoc-openapi-maven-plugin для создания описаний OpenAPI в форматах json и yaml .

Плагин springdoc-openapi-maven- plugin работает с плагином spring-boot-maven . Maven запускает подключаемый модуль openapi на этапе интеграционного тестирования .

Давайте посмотрим, как мы можем настроить плагин в нашем pom.xml :

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.3.RELEASE</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>0.2</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>

Мы также можем настроить плагин для использования пользовательских значений:

<plugin>
<executions>
.........
</executions>
<configuration>
<apiDocsUrl>http://localhost:8080/v3/api-docs</apiDocsUrl>
<outputFileName>openapi.json</outputFileName>
<outputDir>${project.build.directory}</outputDir>
</configuration>
</plugin>

Давайте подробнее рассмотрим параметры, которые мы можем настроить для плагина:

  • apiDocsUrl — URL-адрес, по которому можно получить доступ к документам в формате JSON, по умолчанию http://localhost:8080/v3/api-docs.
  • outputFileName — имя файла, в котором хранятся определения, по умолчанию — openapi.json.
  • outputDir — абсолютный путь к каталогу, в котором хранятся документы, по умолчанию ${project.build.directory}

7. Автоматическая генерация документов с использованием проверки компонентов JSR-303

Когда наша модель включает аннотации проверки бина JSR-303, такие как @NotNull , @NotBlank , @Size , @Min и @Max , библиотека springdoc-openapi использует их для создания дополнительной документации схемы для соответствующих ограничений.

Давайте посмотрим на пример, используя наш bean-компонент Book :

public class Book {

private long id;

@NotBlank
@Size(min = 0, max = 20)
private String title;

@NotBlank
@Size(min = 0, max = 30)
private String author;

}

Теперь документация, сгенерированная для компонента Book , стала немного более информативной:

./31b48bbba1bf9f2f2facffbef55031b9.png

8. Создайте документацию, используя @ControllerAdvice и @ResponseStatus

Использование @ResponseStatus для методов в классе @RestControllerAdvice автоматически создаст документацию для кодов ответов. В этом классе @RestControllerAdvice два метода аннотированы @ResponseStatus :

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

@ExceptionHandler(ConversionFailedException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<String> handleConnversion(RuntimeException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(BookNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<String> handleBookNotFound(RuntimeException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}

В результате теперь мы можем увидеть документацию для кодов ответа 400 и 404:

./393f700cfeb5ae6076077cfc80ee817a.png

9. Создайте документацию, используя @Operation и @ApiResponses

Далее давайте посмотрим, как мы можем добавить некоторое описание к нашему API, используя пару аннотаций, специфичных для OpenAPI .

Для этого мы аннотируем конечную точку /api/book/{id} нашего контроллера с помощью @Operation и @ApiResponses :

@Operation(summary = "Get a book by its id")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Found the book",
content = { @Content(mediaType = "application/json",
schema = @Schema(implementation = Book.class)) }),
@ApiResponse(responseCode = "400", description = "Invalid id supplied",
content = @Content),
@ApiResponse(responseCode = "404", description = "Book not found",
content = @Content) })
@GetMapping("/{id}")
public Book findById(@Parameter(description = "id of book to be searched")
@PathVariable long id) {
return repository.findById(id).orElseThrow(() -> new BookNotFoundException());
}

Вот эффект:

./9a79da74cb5afc3861d2b426ac990b3f.png

Как мы видим, текст, который мы добавили в @Operation , находится на уровне операции API. Точно так же описание, добавленное к различным элементам @ApiResponse в аннотации контейнера @ApiResponses , также отображается здесь, добавляя смысл нашим ответам API.

Очевидно, мы не получаем никакой схемы для ответов 400 и 404 выше. Поскольку мы определили для них пустой @Content , отображаются только их описания.

10. Поддержка Котлина

Поскольку Spring Boot 2.x имеет первоклассную поддержку Kotlin, SpringDoc поддерживает этот язык JVM из коробки для приложений Boot 2.x.

Чтобы увидеть это в действии, мы создадим простой Foo API в Kotlin.

После первоначальной настройки мы добавим класс данных и контроллер. Мы добавим их в подпакет нашего загрузочного приложения, чтобы при запуске он выбирал наш FooController вместе с более ранним BookController :

@Entity
data class Foo(
@Id
val id: Long = 0,

@NotBlank
@Size(min = 0, max = 50)
val name: String = ""
)

@RestController
@RequestMapping("/")
class FooController() {
val fooList: List = listOf(Foo(1, "one"), Foo(2, "two"))

@Operation(summary = "Get all foos")
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Found Foos", content = [
(Content(mediaType = "application/json", array = (
ArraySchema(schema = Schema(implementation = Foo::class)))))]),
ApiResponse(responseCode = "400", description = "Bad request", content = [Content()]),
ApiResponse(responseCode = "404", description = "Did not find any Foos", content = [Content()])]
)
@GetMapping("/foo")
fun getAllFoos(): List = fooList
}

Теперь, когда мы нажмем URL-адрес документации нашего API, мы также увидим Foo API:

./ebfb83dc5416948494bde14c85f84d6b.png

Чтобы улучшить поддержку типов Kotlin, мы можем добавить эту зависимость:

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-kotlin</artifactId
<version>1.6.4</version>
</dependency>

После этого наша схема Foo будет выглядеть более информативно, как это было, когда мы добавили JSR-303 Bean Validation:

./fa7ab1cbe859029413adf39c731a494a.png

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

В этой статье мы научились настраивать springdoc-openapi в наших проектах. Затем мы увидели, как интегрировать springdoc-openapi с пользовательским интерфейсом Swagger. Мы также видели, как это сделать с проектами Spring Webflux.

Затем мы использовали подключаемый модуль Springdoc-openapi Maven для создания определений OpenAPI для наших API и увидели, как предоставлять информацию о разбиении на страницы и сортировке из данных Spring. После этого мы рассмотрели, как springdoc-openapi автоматически генерирует документацию, используя аннотации проверки бина JSR 303 и аннотации @ResponseStatus в классе @ControllerAdvice .

Мы также узнали, как добавить описание к нашему API, используя несколько аннотаций, специфичных для OpenAPI. Наконец, мы взглянули на поддержку Kotlin в OpenAPI.

Springdoc-openapi создает документацию по API в соответствии со спецификацией OpenAPI 3. Кроме того, он также обрабатывает для нас конфигурацию пользовательского интерфейса Swagger, что делает создание документа API довольно простой задачей.

Как всегда, код доступен на GitHub .