В настоящее время открытые API наконец получают то внимание, которого заслуживают, и компании начинают осознавать их стратегическую ценность. Тем не менее, работа с API сторонних производителей может быть очень утомительной, особенно если эти API не поддерживаются, плохо спроектированы или не содержат никакой документации. Вот почему я решил поискать способы предоставить коллегам-программистам и другим членам команды надлежащую документацию, когда дело доходит до интеграции. Один из способов — использовать WADL, который является стандартом, специально разработанным для описания веб-приложений на основе HTTP (например, веб-сервисов REST). Однако при использовании WADL есть несколько недостатков, которые заставили меня искать решения для правильного документирования и предоставления документации API.
развязность
Другим способом может быть пойти с Swagger . Swagger — это реализация спецификации и фреймворка, которая поддерживает полный жизненный цикл разработки веб-сервисов RESTful. Сама спецификация не зависит от языка, что может пригодиться в гетерогенной среде. Swagger также поставляется с модулем пользовательского интерфейса Swagger, который позволяет программистам и другим членам команды эффективно взаимодействовать с API и дает им возможность работать с ним, обеспечивая при этом доступ к документации.
Пример весны с Джерси
Не так давно я наткнулся на статью, описывающую спецификацию Swagger, и я был заинтригован, чтобы попробовать. В то время я работал над милым маленьким микросервисом, поэтому у меня был идеальный полигон для его тестирования. Исходя из этого, я подготовил небольшой пример того, как использовать Swagger в вашем приложении, когда вы используете Spring Framework и Jersey. Примеры моделей кода упрощают REST API для подмножества возможных API в сценарии приложения магазина.
Примечание. Объявления импорта были пропущены во всех примерах кода Java.
Джерси сервлет
Прежде чем мы начнем знакомство с Swagger в нашем коде, давайте немного поговорим о нашем примере. Прежде всего, давайте посмотрим на web.xml . Ниже приведен простой старый web.xml с несколькими простыми объявлениями и сопоставлениями. Здесь нет ничего особенного, просто куча настроек.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<web-app id="SpringWithSwagger" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring Jersey Swagger Example</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>jersey-serlvet</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.jakubstas.swagger.SpringWithSwagger</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey-serlvet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping></web-app> |
Конечная точка
Второе, что нам понадобится, — это конечная точка, которая определяет нашу службу REST — например, конечная точка сотрудника для перечисления текущих сотрудников. Еще раз, нет ничего экстраординарного, только несколько открытых методов, обеспечивающих базовую функциональность API.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package com.jakubstas.swagger.rest;@Path("/employees")public class EmployeeEndpoint { private List<Employee> employees = new ArrayList<Employee>(); { final Employee employee = new Employee(); employee.setEmployeeNumber(1); employee.setFirstName("Jakub"); employee.setSurname("Stas"); employees.add(employee); } @OPTIONS public Response getProductsOptions() { final String header = HttpHeaders.ALLOW; final String value = Joiner.on(", ").join(RequestMethod.GET, RequestMethod.OPTIONS).toString(); return Response.noContent().header(header, value).build(); } @GET @Produces(MediaType.APPLICATION_JSON) public Response getEmployees() { return Response.ok(employees).build(); }} |
Swagger зависимости
Первое, что нам нужно сделать, это включить все необходимые зависимости Swagger в наш pom.xml как показано ниже (к pom.xml для нас, это всего лишь одна зависимость).
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <properties> ... <swagger-version>1.3.8</swagger-version> ... </properties> ... <dependencies> ... <!-- Swagger --> <dependency> <groupId>com.wordnik</groupId> <artifactId>swagger-jersey2-jaxrs_2.10</artifactId> <version>${swagger-version}</version> </dependency> ... </dependencies></project> |
Конфигурация Swagger
Теперь давайте посмотрим, как Swagger интегрируется в наш пример. Как и при любом введении новой зависимости в вашем проекте, вы должны быть обеспокоены тем, насколько инвазивным и дорогостоящим будет этот процесс. Единственными затронутыми местами будут ваши конечные точки REST, конфигурация Spring и некоторые объекты переноса (если вы решите включить их), как вы увидите в следующих примерах кода. Это означает, что в web.xml не требуется настройка для работы Swagger с вашим приложением Spring, а это означает, что он довольно неинвазивен и остается ограниченным в области API.
Вам нужно три основных свойства для работы Swagger:
- Версия API
- Предоставляет версию API приложения.
- базовый путь
- Корневой URL, обслуживающий API
- пакет ресурсов
- Определяет пакет, где искать аннотации Swagger
Поскольку за поддержку API в первую очередь отвечают аналитики и программисты, мне нравится хранить эту конфигурацию в отдельном файле свойств, который называется swagger.properties . Таким образом, он не смешивается с конфигурацией приложения и с меньшей вероятностью будет изменен случайно. Следующий фрагмент изображает такой файл конфигурации.
|
1
2
3
|
swagger.apiVersion=1.0swagger.basePath=http://[hostname/ip address]:[port]/SpringWithSwagger/restswagger.resourcePackage=com.jakubstas.swagger.rest |
Для второй части конфигурации я создал компонент конфигурации, использующий ранее упомянутые свойства. Используя аннотацию Spring @PostConstruct предоставляющую хук жизненного цикла бина, мы можем создавать и устанавливать определенные атрибуты, которые требует Swagger, но не может получить (по крайней мере, в текущей версии).
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package com.jakubstas.swagger.rest.config;/** * Configuration bean to set up Swagger. */@Componentpublic class SwaggerConfiguration { @Value("${swagger.resourcePackage}") private String resourcePackage; @Value("${swagger.basePath}") private String basePath; @Value("${swagger.apiVersion}") private String apiVersion; @PostConstruct public void init() { final ReflectiveJaxrsScanner scanner = new ReflectiveJaxrsScanner(); scanner.setResourcePackage(resourcePackage); ScannerFactory.setScanner(scanner); ClassReaders.setReader(new DefaultJaxrsApiReader()); final SwaggerConfig config = ConfigFactory.config(); config.setApiVersion(apiVersion); config.setBasePath(basePath); } public String getResourcePackage() { return resourcePackage; } public void setResourcePackage(String resourcePackage) { this.resourcePackage = resourcePackage; } public String getBasePath() { return basePath; } public void setBasePath(String basePath) { this.basePath = basePath; } public String getApiVersion() { return apiVersion; } public void setApiVersion(String apiVersion) { this.apiVersion = apiVersion; }} |
Последний шаг — объявить следующие три боба Swagger: ApiListingResourceJSON , ApiDeclarationProvider и ResourceListingProvider .
|
1
2
3
4
5
6
7
8
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.jakubstas.swagger" /> <context:property-placeholder location="classpath:swagger.properties" /> <bean class="com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON" /> <bean class="com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider" /> <bean class="com.wordnik.swagger.jaxrs.listing.ResourceListingProvider" /></beans> |
Swagger теперь настроен, и вы можете проверить, правильно ли работает ваша установка. Просто введите URL-адрес из вашей переменной basePath а затем /api-docs в ваш браузер и проверьте результат. В моем примере вы должны увидеть вывод, подобный следующему фрагменту, который я получил после доступа к http://[hostname]:[port]/SpringWithSwagger/rest/api-docs/ .
|
1
|
{"apiVersion":"1.0","swaggerVersion":"1.2"} |
Что дальше?
Если вы выполнили все шаги, у вас должна быть рабочая настройка, чтобы начать с документации API. Я продемонстрирую, как описывать API с помощью аннотаций Swagger, в моей следующей статье под названием Spring Rest API with Swagger — Создание документации. Код, используемый в этой микросерии, опубликован на GitHub и содержит примеры для всех обсуждаемых функций и инструментов. Пожалуйста, наслаждайтесь!
| Ссылка: | Spring Rest API с Swagger — интеграция и настройка от нашего партнера JCG Якуба Стаса в блоге |