Статьи

Spring Rest API с Swagger — интеграция и настройка

В настоящее время открытые 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
    <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
    ...
    <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.0
swagger.basePath=http://[hostname/ip address]:[port]/SpringWithSwagger/rest
swagger.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.
 */
@Component
public 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
    <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 Якуба Стаса в блоге