
Документация REST сервисов часто устаревает, при каких то небольших изменениях в коде. Для поддерживания документации сервисов в актуальном виде есть замечательный инструмент Swagger. Генерируется и обновляется автоматически, поддерживает форматы JSON, либо YAML.
Использовал:
Swagger | Spring Boot | H2 In-memory Database | Spring Data JPA |
Необходимо выполнить:
– Реализовать REST сервис на Spring Boot;
– Подключить фреймворк Swagger UI;
Для сборки Spring проекта удобно использовать Spring Initializr
Задаем структуру проекта и реализовываем небольшой REST сервис.
Далее необходимо добавить несколько зависимостей в pom.xml
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> |
Где artifactId springfox-swagger2 подключение документации по JSON API для Spring-приложений.
artifactId springfox-swagger-ui для возможности подключения UI интерфейса.
Для проекта Spring Boot необходимо добавить только один Bean с конфигурацией Swagger:
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } } |
Bean Docket содержит конфигурацию для Swagger 2, как по умолчанию так и с возможностью кастомизации.
Где,
@Configuration Spring аннотация, сообщает контейнеру Spring о наличии одного или нескольких компонентов, с которыми необходимо работать во время выполнения, также возможно конфигурирование через xml файлы;
@EnableSwagger2 аннотация включает поддержку Swagger 2 в классе для нашего Spring Boot приложения. Должна сопровождаться аннотацией @Configuration;
@Bean Стандартная Spring аннотация, создает и регистрирует компонент;
Docket основной механизм настройки API, инициализирован для спецификации Swagger. Интерфейс предоставляет конфигурацию по умолчанию и удобные методы для настройки;
.select() метод возвращает экземпляр ApiSelectorBuilder, который предоставляет способ управления endpoints, предоставляемыми Swagger;
.apis() определяет базовый пакет, который будет сканирован и будут созданы API для всех классов в нем.
Примеры:
.apis(RequestHandlerSelectors.any()) указывает на генерацию документации для всех пакетов.
.apis(RequestHandlerSelectors.basePackage(“ru.gotoqa.GameOfThronesService”)) ограничено пакетом GameOfThronesService.
.paths() метод дополнительно определяет, для каких путей в наших API мы хотим создать документацию.
Примеры:
.paths(PathSelectors.any()) включает все endpoints для создания документации.
.paths(regex(“/version1.*”)) все endpoints которые попадают под маску “/version1.*” будут задокументированы.
.paths(Predicates.or(PathSelectors.regex(“/version1.*”),PathSelectors.regex(“/version2.*”))) ограничение по нескольким endpoints.
Немного кастомизации из коробки
Через метод .apiInfo(apiInfo()) можно добавить информацию о владельце, компании etc.
private ApiInfo apiInfo() { return new ApiInfo( "REST API Game Of Thrones Service", "", "API 1.0", "http://gotoqa.ru/cv/", new Contact("Roman", "www.gotoqa.ru", "n@company.com"), "License of API", "http://gotoqa.ru", Collections.emptyList()); } |
String title, String description, String version, String termsOfServiceUrl, Contact contact, String license, String licenseUrl, Collection<VendorExtension> vendorExtensions |
Swagger Core аннотации для контроллера. Doc’s
@Api | Помечает класс как Swagger resource. |
@ApiModel | Provides additional information about Swagger models. |
@ApiModelProperty | Adds and manipulates data of a model property. |
@ApiOperation | Описание HTTP метода |
@ApiParam | Adds additional meta-data for operation parameters. |
@ApiResponse | Describes a possible response of an operation. |
@ApiResponses |
A wrapper to allow a list of multiple ApiResponse objects. |
@RestController //@RequestMapping("/gameofthrones") @Api(value="GameOfThronesService", description="Actor WEB Service") public class ActorController { @Autowired private ActorRepository actorRepository; @GetMapping("/version1/actors") @ApiOperation(value = "Returns list of all Actors") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully retrieved list"), @ApiResponse(code = 401, message = "You are not authorized to view the resource"), @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"), @ApiResponse(code = 404, message = "The resource you were trying to reach is not found") } ) List<Actor> findAll(){ return actorRepository.findAll(); } @ResponseStatus(HttpStatus.CREATED) @PostMapping("/version1/actors") Actor newActor(@RequestBody Actor actor){ return actorRepository.save(actor); } @GetMapping("/version1/actors/{id}") @ApiOperation(value = "Returns Actor data") Actor findOne(@ApiParam("Id of the Actors to be obtained. Cannot be empty.") @PathVariable Long id) { return actorRepository.findById(id) .orElseThrow(() -> new ActorNotFoundException(id)); } |
Аннотация @ApiModelProperty используется для описания модели БД.
@Getter @Setter @Entity @NoArgsConstructor public class Actor { @Id @GeneratedValue @ApiModelProperty(notes = "The database generated actor's ID") private Long id; @ApiModelProperty(notes = "Actor first name", required = true) private String firstName; @ApiModelProperty(notes = "Actor second name", required = true) private String lastName; @ApiModelProperty(notes = "Actor birthDay", required = true) private String birthDay; public Actor(String firstName, String lastName, String birthDay) { this.firstName = firstName; this.lastName = lastName; this.birthDay = birthDay; } } |
В завершение пример UI работы Swagger (/swagger-ui.html)
Рассмотренные выше примеры не полностью охватывают функционал Swagger фреймворка. Из особо примечательных стоит упомянуть про возможность переопределения стандартных ответов HTTP методов и авторизация. Так как оба случая частные расписывать их использование не стал.
Ссылка на полную версию проекта на GitHub:
Github GameOfThronesService