[Java] Документирование API в Java приложении с помощью Swagger v3
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Веб-приложение часто содержит API для взаимодействия с ним. Документирование API позволит клиентам быстрее понять, как использовать ваши сервисы. Если API закрыт от внешнего мира, то все равно стоит уделить время спецификации — это поможет вашим новым коллегам быстрее разобраться с системой.
Создание документации вручную — утомительный процесс. Swagger поможет вам упростить эту работу.
Что такое Swagger?
Swagger автоматически генерирует документацию API в виде json. А проект Springdoc создаст удобный UI для визуализации. Вы не только сможете просматривать документацию, но и отправлять запросы, и получать ответы.
Также возможно сгенерировать непосредственно клиента или сервер по спецификации API Swagger, для этого нужен генератор кода Swagger-Codegen.
Swagger использует декларативный подход, все как мы любим. Размечаете аннотациями методы, параметры, DTO.
Вы найдете все примеры представленные тут в моем репозитории.
Создание REST API
Чтобы документировать API, для начала напишем его :smile: Вы можете перейти к следующей главе, чтобы не тратить время.
Добавим примитивные контроллеры и одно DTO. Суть нашей системы — программа лояльности пользователей.
Для наших примеров достаточно слоя контроллеров, поэтому я позволю себе вольность опустить серверный и репозиторный слой и добавить бизнес логику в контроллер. В своих проектах старайтесь так не делать.
В качестве DTO у нас будет класс UserDto — это пользователь нашей системы. У него пять полей, из которых 3 обязательны: имя, уникальный ключ, пол пользователя, количество баллов, дата регистрации
public class UserDto {
private String key;
private String name;
private Long points = 0L;
private Gender gender;
private LocalDateTime regDate = LocalDateTime.now();
public UserDto() {
}
public UserDto(String key, String name, Gender gender) {
this.key = key;
this.name = name;
this.gender = gender;
}
public static UserDto of(String key, String value, Gender gender) {
return new UserDto(key, value, gender);
}
// getters and setters
}
public enum Gender {
MAN, WOMAN
}
Для взаимодействия с нашей бизнес-логикой, добавим три контроллера: UserController, PointContoller, SecretContoller.
UserController отвечает за добавление, обновление и получение пользователей.
@RestController
@RequestMapping("/api/user")
public class UserController {
private final Map<String, UserDto> repository;
public UserController(Map<String, UserDto> repository) {
this.repository = repository;
}
@PutMapping(produces = APPLICATION_JSON_VALUE)
public HttpStatus registerUser(@RequestBody UserDto userDto) {
repository.put(userDto.getKey(), userDto);
return HttpStatus.OK;
}
@PostMapping(produces = APPLICATION_JSON_VALUE)
public HttpStatus updateUser(@RequestBody UserDto userDto) {
if (!repository.containsKey(userDto.getKey())) return HttpStatus.NOT_FOUND;
repository.put(userDto.getKey(), userDto);
return HttpStatus.OK;
}
@GetMapping(value = "{key}", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<UserDto> getSimpleDto(@PathVariable("key") String key) {
return ResponseEntity.ok(repository.get(key));
}
}
PointContoller отвечает за взаимодействие с баллами пользователя. Один метод этого контроллера отвечает за добавление и удаление балов пользователям.
@RestController
@RequestMapping("api/user/point")
public class PointController {
private final Map<String, UserDto> repository;
public PointController(Map<String, UserDto> repository) {
this.repository = repository;
}
@PostMapping("{key}")
public HttpStatus changePoints(
@PathVariable String key,
@RequestPart("point") Long point,
@RequestPart("type") String type
) {
final UserDto userDto = repository.get(key);
userDto.setPoints(
"plus".equalsIgnoreCase(type)
? userDto.getPoints() + point
: userDto.getPoints() - point
);
return HttpStatus.OK;
}
}
Метод destroy в SecretContoller может удалить всех пользователей.
@RestController
@RequestMapping("api/secret")
public class SecretController {
private final Map<String, UserDto> repository;
public SecretController(Map<String, UserDto> repository) {
this.repository = repository;
}
@GetMapping(value = "destroy")
public HttpStatus destroy() {
repository.clear();
return HttpStatus.OK;
}
}
Настраиваем Swagger
Теперь добавим Swagger в наш проект. Для этого добавьте следующие зависимости в проект.
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.2</version>
</dependency>
Swagger автоматически находит список всех контроллеров, определенных в нашем приложении. При нажатии на любой из них будут перечислены допустимые методы HTTP (DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT).
Для каждого метода доступные следующие данные: статус ответа, тип содержимого и список параметров.
Поэтому после добавления зависимостей, у нас уже есть документация. Чтобы убедиться в этом, переходим по адресу: localhost:8080/swagger-ui.html
Также можно вызвать каждый метод с помощью пользовательского интерфейса. Откроем метод добавления пользователей.
Пока у нас не очень информативная документация. Давайте исправим это.
Для начала создадим класс конфигурации сваггера SwaggerConfig — имя произвольное.
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(
new Info()
.title("Example Swagger Api")
.version("1.0.0")
);
}
}
- title — это название вашего приложения
- version — версия вашего API
Эти данные больше для визуальной красоты UI документации.
Добавление авторов
Добавьте разработчиков API, чтобы было понятно, кто в ответе за это безобразие
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(
new Info()
.title("Loyalty System Api")
.version("1.0.0")
.contact(
new Contact()
.email("me@upagge.ru")
.url("https://uPagge.ru")
.name("Struchkov Mark")
)
);
}
Разметка контроллеров
Переопределим описания контроллеров, чтобы сделать документацию понятнее. Для этого пометим контроллеры аннотацией @Tag.
@Tag(name="Название контроллера", description="Описание контролера")
public class ControllerName {
// ... ... ... ... ...
}
Скрыть контроллер
У нас есть контроллер, который мы хотим скрыть — SecretController. Аннотация @Hidden поможет нам в этом.
@Hidden
@Tag(name = "Секретный контролер", description = "Позволяет удалить всех пользователей")
public class SecretController {
// ... ... ... ... ...
}
Аннотация скрывает контроллер только из Swagger. Он все также доступен для вызова. Используйте другие методы для защиты вашего API.
Наша документация стала намного понятнее, но давайте добавим описания для каждого метода контроллера.
Разметка методов
Аннотация @Operation описывает возможности методов контроллера. Достаточно определить следующие значения:
- summary — короткое описание.
- description — более полное описание.
@Operation(
summary = "Регистрация пользователя",
description = "Позволяет зарегистрировать пользователя"
)
public HttpStatus registerUser(@RequestBody UserDto userDto) {
// ... ... ... ... ...
}
Разметка переменных метода
При помощи аннотации Parameter также опишем переменные в методе, который отвечает за управление баллами пользователей.
public HttpStatus changePoints(
@PathVariable @Parameter(description = "Идентификатор пользователя") String key,
@RequestPart("point") @Parameter(description = "Количество баллов") Long point,
@RequestPart("type") @Parameter(description = "Тип операции") TypeOperation type
) {
// ... ... ... ... ...
}
С помощью параметра required можно задать обязательные поля для запроса. По умолчанию все поля необязательные.
Разметка DTO
Разработчики стараются называть переменные в классе понятными именами, но не всегда это помогает. Вы можете дать человеко-понятное описание самой DTO и ее переменным с помощью аннотации @Schema
@Schema(description = "Сущность пользователя")
public class UserDto {
@Schema(description = "Идентификатор")
private String key;
// ... ... ... ... ...
}
Сваггер заполнит переменные, формат которых он понимает: enum, даты. Но если некоторые поля DTO имеют специфичный формат, то помогите разработчикам добавив пример.
@Schema(description = "Идентификатор", example = "A-124523")
Выглядеть это будет так:
Но подождите, зачем мы передаем дату регистрации. Да и уникальный ключ чаще всего будет задаваться сервером. Скроем эти поля из swagger с помощью параметра Schema.AccessMode.READ_ONLY:
public class UserDto {
@Schema(accessMode = Schema.AccessMode.READ_ONLY)
private String key;
...
}
Валидация
Добавим валидацию в метод управления баллами пользователя в PointController. Мы не хотим, чтобы можно было передать отрицательные баллы.
Подробнее о валидации данных в этой статье.
public HttpStatus changePoints(
// ... ... ... ... ...
@RequestPart("point") @Min(0) @Parameter(description = "Количество баллов") Long point,
// ... ... ... ... ...
) {
// ... ... ... ... ...
}
Давайте посмотрим на изменения спецификации. Для поля point появилось замечание minimum: 0.
И все это нам не стоило ни малейшего дополнительного усилия.
Итог
Этих знаний вам хватит, чтобы сделать хорошее описание API вашего проекта.
Если нужны более тонкие настройки, то вы без труда сможете разобраться открыв документацию к аннотациям сваггера.
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript, Программирование, Java, Микросервисы] Мониторинг бизнес-процессов Camunda
- [Java] Передача даты с формы в базу
- [Java] Еще одна p2p overlay сеть
- [Программирование, Java, Компиляторы] Java HotSpot JIT компилятор — устройство, мониторинг и настройка (часть 1)
- [Java, C++, Разработка под Android] Android interop with SWIG (a guide). From simple to weird. Part 1 — simple
- [Разработка веб-сайтов, JavaScript, HTML, ReactJS] React.js — формошлепство или работа с формами при помощи пользовательских хуков
- [Ненормальное программирование, JavaScript, Google Chrome, PDF] Пугающие эксперименты с PDF: запускаем «Арканоид» в документе (перевод)
- [JavaScript, TensorFlow] Фронтендер пишет нейронки. Уровень сложности «хочу на ручки»
- [JavaScript, Программирование, Atlassian] Как я подружил BPMN и Bitbucket
- [Java] Фреймворк Camel: сравнение компонентов HTTP и AHC
Теги для поиска: #_java, #_swagger, #_spring, #_java, #_api, #_rest, #_dokumentirovanie (документирование), #_java
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:38
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Веб-приложение часто содержит API для взаимодействия с ним. Документирование API позволит клиентам быстрее понять, как использовать ваши сервисы. Если API закрыт от внешнего мира, то все равно стоит уделить время спецификации — это поможет вашим новым коллегам быстрее разобраться с системой. Создание документации вручную — утомительный процесс. Swagger поможет вам упростить эту работу. Что такое Swagger? Swagger автоматически генерирует документацию API в виде json. А проект Springdoc создаст удобный UI для визуализации. Вы не только сможете просматривать документацию, но и отправлять запросы, и получать ответы. Также возможно сгенерировать непосредственно клиента или сервер по спецификации API Swagger, для этого нужен генератор кода Swagger-Codegen. Swagger использует декларативный подход, все как мы любим. Размечаете аннотациями методы, параметры, DTO. Вы найдете все примеры представленные тут в моем репозитории. Создание REST API Чтобы документировать API, для начала напишем его :smile: Вы можете перейти к следующей главе, чтобы не тратить время. Добавим примитивные контроллеры и одно DTO. Суть нашей системы — программа лояльности пользователей. Для наших примеров достаточно слоя контроллеров, поэтому я позволю себе вольность опустить серверный и репозиторный слой и добавить бизнес логику в контроллер. В своих проектах старайтесь так не делать. В качестве DTO у нас будет класс UserDto — это пользователь нашей системы. У него пять полей, из которых 3 обязательны: имя, уникальный ключ, пол пользователя, количество баллов, дата регистрации public class UserDto {
private String key; private String name; private Long points = 0L; private Gender gender; private LocalDateTime regDate = LocalDateTime.now(); public UserDto() { } public UserDto(String key, String name, Gender gender) { this.key = key; this.name = name; this.gender = gender; } public static UserDto of(String key, String value, Gender gender) { return new UserDto(key, value, gender); } // getters and setters } public enum Gender {
MAN, WOMAN } Для взаимодействия с нашей бизнес-логикой, добавим три контроллера: UserController, PointContoller, SecretContoller. UserController отвечает за добавление, обновление и получение пользователей. @RestController
@RequestMapping("/api/user") public class UserController { private final Map<String, UserDto> repository; public UserController(Map<String, UserDto> repository) { this.repository = repository; } @PutMapping(produces = APPLICATION_JSON_VALUE) public HttpStatus registerUser(@RequestBody UserDto userDto) { repository.put(userDto.getKey(), userDto); return HttpStatus.OK; } @PostMapping(produces = APPLICATION_JSON_VALUE) public HttpStatus updateUser(@RequestBody UserDto userDto) { if (!repository.containsKey(userDto.getKey())) return HttpStatus.NOT_FOUND; repository.put(userDto.getKey(), userDto); return HttpStatus.OK; } @GetMapping(value = "{key}", produces = APPLICATION_JSON_VALUE) public ResponseEntity<UserDto> getSimpleDto(@PathVariable("key") String key) { return ResponseEntity.ok(repository.get(key)); } } PointContoller отвечает за взаимодействие с баллами пользователя. Один метод этого контроллера отвечает за добавление и удаление балов пользователям. @RestController
@RequestMapping("api/user/point") public class PointController { private final Map<String, UserDto> repository; public PointController(Map<String, UserDto> repository) { this.repository = repository; } @PostMapping("{key}") public HttpStatus changePoints( @PathVariable String key, @RequestPart("point") Long point, @RequestPart("type") String type ) { final UserDto userDto = repository.get(key); userDto.setPoints( "plus".equalsIgnoreCase(type) ? userDto.getPoints() + point : userDto.getPoints() - point ); return HttpStatus.OK; } } Метод destroy в SecretContoller может удалить всех пользователей. @RestController
@RequestMapping("api/secret") public class SecretController { private final Map<String, UserDto> repository; public SecretController(Map<String, UserDto> repository) { this.repository = repository; } @GetMapping(value = "destroy") public HttpStatus destroy() { repository.clear(); return HttpStatus.OK; } } Настраиваем Swagger Теперь добавим Swagger в наш проект. Для этого добавьте следующие зависимости в проект. <dependency>
<groupId>io.swagger.core.v3</groupId> <artifactId>swagger-annotations</artifactId> <version>2.1.6</version> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.5.2</version> </dependency> Swagger автоматически находит список всех контроллеров, определенных в нашем приложении. При нажатии на любой из них будут перечислены допустимые методы HTTP (DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT). Для каждого метода доступные следующие данные: статус ответа, тип содержимого и список параметров. Поэтому после добавления зависимостей, у нас уже есть документация. Чтобы убедиться в этом, переходим по адресу: localhost:8080/swagger-ui.html Также можно вызвать каждый метод с помощью пользовательского интерфейса. Откроем метод добавления пользователей. Пока у нас не очень информативная документация. Давайте исправим это. Для начала создадим класс конфигурации сваггера SwaggerConfig — имя произвольное. @Configuration
public class SwaggerConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .info( new Info() .title("Example Swagger Api") .version("1.0.0") ); } }
Эти данные больше для визуальной красоты UI документации. Добавление авторов Добавьте разработчиков API, чтобы было понятно, кто в ответе за это безобразие @Bean
public OpenAPI customOpenAPI() { return new OpenAPI() .info( new Info() .title("Loyalty System Api") .version("1.0.0") .contact( new Contact() .email("me@upagge.ru") .url("https://uPagge.ru") .name("Struchkov Mark") ) ); } Разметка контроллеров Переопределим описания контроллеров, чтобы сделать документацию понятнее. Для этого пометим контроллеры аннотацией @Tag. @Tag(name="Название контроллера", description="Описание контролера")
public class ControllerName { // ... ... ... ... ... } Скрыть контроллер У нас есть контроллер, который мы хотим скрыть — SecretController. Аннотация @Hidden поможет нам в этом. @Hidden
@Tag(name = "Секретный контролер", description = "Позволяет удалить всех пользователей") public class SecretController { // ... ... ... ... ... } Аннотация скрывает контроллер только из Swagger. Он все также доступен для вызова. Используйте другие методы для защиты вашего API. Наша документация стала намного понятнее, но давайте добавим описания для каждого метода контроллера. Разметка методов Аннотация @Operation описывает возможности методов контроллера. Достаточно определить следующие значения:
@Operation(
summary = "Регистрация пользователя", description = "Позволяет зарегистрировать пользователя" ) public HttpStatus registerUser(@RequestBody UserDto userDto) { // ... ... ... ... ... } Разметка переменных метода При помощи аннотации Parameter также опишем переменные в методе, который отвечает за управление баллами пользователей. public HttpStatus changePoints(
@PathVariable @Parameter(description = "Идентификатор пользователя") String key, @RequestPart("point") @Parameter(description = "Количество баллов") Long point, @RequestPart("type") @Parameter(description = "Тип операции") TypeOperation type ) { // ... ... ... ... ... } С помощью параметра required можно задать обязательные поля для запроса. По умолчанию все поля необязательные. Разметка DTO Разработчики стараются называть переменные в классе понятными именами, но не всегда это помогает. Вы можете дать человеко-понятное описание самой DTO и ее переменным с помощью аннотации @Schema @Schema(description = "Сущность пользователя")
public class UserDto { @Schema(description = "Идентификатор") private String key; // ... ... ... ... ... } Сваггер заполнит переменные, формат которых он понимает: enum, даты. Но если некоторые поля DTO имеют специфичный формат, то помогите разработчикам добавив пример. @Schema(description = "Идентификатор", example = "A-124523")
Выглядеть это будет так: Но подождите, зачем мы передаем дату регистрации. Да и уникальный ключ чаще всего будет задаваться сервером. Скроем эти поля из swagger с помощью параметра Schema.AccessMode.READ_ONLY: public class UserDto {
@Schema(accessMode = Schema.AccessMode.READ_ONLY) private String key; ... } Валидация Добавим валидацию в метод управления баллами пользователя в PointController. Мы не хотим, чтобы можно было передать отрицательные баллы. Подробнее о валидации данных в этой статье. public HttpStatus changePoints(
// ... ... ... ... ... @RequestPart("point") @Min(0) @Parameter(description = "Количество баллов") Long point, // ... ... ... ... ... ) { // ... ... ... ... ... } Давайте посмотрим на изменения спецификации. Для поля point появилось замечание minimum: 0. И все это нам не стоило ни малейшего дополнительного усилия. Итог Этих знаний вам хватит, чтобы сделать хорошее описание API вашего проекта. Если нужны более тонкие настройки, то вы без труда сможете разобраться открыв документацию к аннотациям сваггера. =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:38
Часовой пояс: UTC + 5