Статьи

Spring Rest API с Swagger – Создание документации

Настоящим ключом к простоте использования REST API является хорошая документация. Но даже если ваша документация выполнена хорошо, вам нужно настроить процессы своей компании так, чтобы она публиковалась правильно и своевременно. Обеспечение своевременного получения заинтересованными сторонами – это одно, но вы также несете ответственность за обновления как API, так и документации. Выполнение этого процесса автоматически обеспечивает легкий выход из проблем, поскольку ваша документация больше не является статичной и становится живой. В предыдущем посте я обсуждал, как интегрировать Swagger в приложение Spring с Jersey. Теперь пришло время показать вам, как создавать документацию и публиковать ее, чтобы ее могли увидеть другие.

Прежде чем перейти к самой документации, давайте начнем с нескольких заметок о ее форме и свойствах. Мы будем использовать аннотации для предоставления метаданных нашему API, который отвечает на вопрос как. Но как насчет почему? С одной стороны, мы поставляем новые аннотации в уже задействованные места, такие как конечные точки API или контроллеры (в случае интеграции со Spring MVC). Но с другой стороны, этот подход имеет выдающееся преимущество в связывании цикла выпуска приложений, API и документации в одной поставке. Использование этого подхода позволяет нам создавать и управлять небольшими связными единицами, обеспечивая надлежащую сегментацию документации, а также ее версионирование.

Создание документации по конечной точке

Все начинается прямо на вашей конечной точке. Чтобы Swagger знал о вашей конечной точке, вам нужно аннотировать свой класс аннотацией @Api . По сути, все, что вы хотите здесь сделать – это назвать конечную точку и дать некоторое описание для ваших пользователей. Это именно то, что я делаю в следующем фрагменте кода. Если вы чувствуете необходимость более подробно ознакомиться с документацией по API, ознакомьтесь с @Api аннотации @Api ниже.

01
02
03
04
05
06
07
08
09
10
package com.jakubstas.swagger.rest;
 
/**
 * REST endpoint for user manipulation.
 */
@Api(value = "users", description = "Endpoint for user management")
@Path("/users")
public class UsersEndpoint {
    ...
}

Чтобы проверить результаты, просто введите URL-адрес из переменной basePath а затем /api-docs в браузер. Это место, где находится список ресурсов для ваших API. Вы можете ожидать что-то похожее на следующий фрагмент, который я получил после аннотирования трех моих конечных точек и доступа к http://[hostname]:[port]/SpringWithSwagger/rest/api-docs/ :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
{
    "apiVersion":"1.0",
    "swaggerVersion":"1.2",
    "apis":[
        {
            "path":"/users",
            "description":"Endpoint for user management"
        },
        {
            "path":"/products",
            "description":"Endpoint for product management"
        },
        {
            "path":"/employees",
            "description":"Endpoint for employee listing"
        }
    ]
}

Однако обратите внимание, что для появления API в списке API необходимо аннотировать как минимум один метод API аннотациями Swagger. Если ни один из ваших методов не аннотирован (или вы еще не предоставили никаких методов), документация по API не будет обработана и опубликована.

@Api аннотация

Описывает API верхнего уровня. Классы с аннотациями @Api будут включены в список ресурсов.

Параметры аннотации:

  • value – краткое описание API
  • description – общее описание этого класса
  • basePath – базовый путь, который предшествует всем элементам @Path
  • position – необязательный явный порядок этого Api в списке ресурсов
  • produces – тип контента, произведенный этим API
  • consumes – тип носителя, потребляемый этим API
  • protocols – протоколы, которые требует этот API (то есть https)
  • authorizations – разрешения, требуемые этим API

Операционная документация

Теперь перейдем к ключевой части документации API. В основном, есть две основные части рабочей документации – описание операции и описание ответа. Начнем с описания операции. Использование аннотации @ApiOperation предоставляет подробное описание того, что делает определенный метод, его ответ, метод HTTP и другую полезную информацию, представленную в описании аннотации ниже. Пример объявления операции для Swagger можно увидеть в следующем примере кода.

@ApiOperation аннотация

Описывает операцию или, как правило, метод HTTP для определенного пути. Операции с эквивалентными путями сгруппированы в массив в объявлении Api.

Параметры аннотации:

  • value – краткое описание операции
  • notes – длинное описание операции
  • response – класс response умолчанию от операции
  • responseContainer – если класс ответа находится внутри контейнера, укажите его здесь
  • tags – в настоящее время не реализованы в читателях, зарезервированы для будущего использования
  • httpMethod – метод HTTP , т.е. GET , PUT , POST , DELETE , PATCH , OPTIONS
  • position – разрешить явное упорядочение операций внутри декларации Api
  • nickname – псевдоним для операции, чтобы переопределить то, что обнаружено сканером аннотаций
  • produces – тип контента, произведенный этим API
  • consumes – тип носителя, потребляемый этим API
  • protocols – протоколы, которые требует этот API (то есть https)
  • authorizations – разрешения, требуемые этим API

Вы можете заметить использование параметра ответа в аннотации @ApiOperation который указывает тип ответа (тип возвращаемого значения) от операции. Как видите, это значение может отличаться от типа возвращаемого значения метода, поскольку оно служит только для целей документации API.

01
02
03
04
05
06
07
08
09
10
11
12
@GET
@Path("/{userName}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Returns user details", notes = "Returns a complete list of users details with a date of last modification.", response = User.class)
@ApiResponses(value = {
    @ApiResponse(code = 200, message = "Successful retrieval of user detail", response = User.class),
    @ApiResponse(code = 404, message = "User with given username does not exist"),
    @ApiResponse(code = 500, message = "Internal server error")}
)
public Response getUser(@ApiParam(name = "userName", value = "Alphanumeric login to the application", required = true) @PathParam("userName") String userName) {
    ...
}

Далее взгляните на использование @ApiParam . Всегда полезно описать клиенту, что вам нужно для выполнения его запроса. Это основная цель аннотации @ApiParam . Независимо от того, работаете ли вы с путем или параметром запроса, вы всегда должны давать пояснения относительно того, что представляет этот параметр.

@ApiParam аннотация

Представляет отдельный параметр в операции Api. Параметр является входом для операции.

Параметры аннотации:

  • name – имя параметра
  • value – описание параметра
  • defaultValue – значение по умолчанию – если, например, нет JAX-RS @DefaultValue
  • allowableValues – описание значений, которые принимает эта конечная точка
  • required – указывает, является ли параметр обязательным или нет
  • access – укажите необязательное значение доступа для фильтрации в реализации Filter . Это позволяет скрыть определенные параметры, если пользователь не имеет к ним доступа
  • allowMultiple – указывает, может ли параметр иметь несколько значений

Наконец, давайте рассмотрим способ документирования фактических ответов метода в терминах сообщений и HTTP-кодов. Swagger поставляется с аннотацией @ApiResponse , которую можно использовать несколько раз, если она обернута с @ApiResponses обертки @ApiResponses . Таким образом, вы можете охватить все альтернативные потоки выполнения вашего кода и предоставить полное описание операций API для клиентов вашего API. Каждый ответ может быть описан в терминах HTTP-кода возврата, описания результата и типа результата. Для более подробной информации о @ApiResponse смотрите описание ниже.

@ApiResponse аннотация

ApiResponse представляет тип ответа от сервера. Это может быть использовано для описания как успешных кодов, так и ошибок. Если ваш Api имеет разные классы ответов, вы можете описать их здесь, связав класс ответов с кодом ответа. Обратите внимание, что Swagger не позволяет использовать несколько типов ответов для одного кода ответа.

Параметры аннотации:

  • codecode ответа для описания
  • message – удобочитаемое сообщение, сопровождающее ответ
  • response – необязательный класс ответа для описания полезной нагрузки сообщения

Использование этих аннотаций довольно просто и обеспечивает хорошо структурированный подход к описанию функций вашего API. Если вы хотите проверить, как выглядит ваша документация, просто введите URL-адрес, указывающий на документацию API одной из ваших конечных точек, добавив значение параметра value из аннотации @Api к URL-адресу, указывающему на список ресурсов. Будьте осторожны, не вводите значение аннотации @Path как ошибку (если они не имеют одинаковое значение). В моем примере желаемый URL-адрес: http://[hostname]:[port]/SpringWithSwagger/rest/api-docs/users . Вы должны увидеть вывод, похожий на следующий фрагмент:

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    "apiVersion":"1.0",
    "swaggerVersion":"1.2",
    "basePath":"http://[hostname/ip address]:[port]/SpringWithSwagger/rest",
    "resourcePath":"/users",
    "apis":[ 
        
            "path":"/users/{userName}",
            "operations":[ 
                
                    "method":"GET",
                    "summary":"Returns user details",
                    "notes":"Returns a complete list of users details with a date of last modification.",
                    "type":"User",
                    "nickname":"getUser",
                    "produces":[ 
                        "application/json"
                    ],
                    "authorizations":{ 
 
                    },
                    "parameters":[ 
                        
                            "name":"userName",
                            "description":"Alphanumeric login to application",
                            "required":true,
                            "type":"string",
                            "paramType":"path",
                            "allowMultiple":false
                        }
                    ],
                    "responseMessages":[ 
                        
                            "code":200,
                            "message":"Successful retrieval of user detail",
                            "responseModel":"User"
                        },
                        
                            "code":404,
                            "message":"User with given username does not exist"
                        },
                        
                            "code":500,
                            "message":"Internal server error"
                        }
                    ]
                }
            ]
        }
    ],
    "models":{
        "User":{
            "id":"User",
            "properties": {
                "surname":{"type":"string"},
                "userName":{"type":"string"},
                "lastUpdated":
                    {
                        "type":"string",
                        "format":"date-time"
                    },
                "avatar":{
                    "type":"array",
                    "items":{"type":"byte"}
                },
                "firstName":{"type":"string"},
                "email":{"type":"string"}
            }
        }
    }
}

Создание модельной документации

Предоставив класс User для параметра response нескольких аннотаций в предыдущем примере, мне удалось добавить новый недокументированный элемент в мою документацию API. Swagger смог извлечь все структурные данные о классе User не обращая внимания на его актуальность для API. Чтобы противостоять этому эффекту, Swagger предоставляет две аннотации для предоставления дополнительной информации пользователям вашего API и ограничения видимости вашей модели. Чтобы пометить класс модели для обработки Swagger, просто поместите @ApiModel поверх вашего класса. Как обычно, вы можете предоставить описание, а также конфигурацию наследования. Для получения дополнительной информации см. Описание @ApiModel ниже.

@ApiModel аннотация

Класс bean, используемый в REST-API. Предположим, у вас есть интерфейс @PUT @ApiOperation(...) void foo(FooBean fooBean) , нет прямого способа увидеть, какие поля будет иметь FooBean . Эта аннотация предназначена для того, чтобы дать описание FooBean а затем FooBean его поля с помощью @ApiModelProperty .

Параметры аннотации:

  • value – предоставить краткий обзор этого класса
  • description – предоставить более подробное описание класса
  • parent – предоставляет суперкласс для модели, позволяющий описывать наследование
  • discriminator – для моделей с базовым классом можно использовать дискриминатор для полиморфных вариантов использования
  • subTypes

Последнее, что вам нужно сделать, это аннотировать членов @ApiModelProperty аннотацией @ApiModelProperty чтобы предоставить документацию для каждого члена класса. Простой пример этого можно увидеть в следующем классе.

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.jakubstas.swagger.model;
 
@ApiModel
public class User {
 
    private String userName;
 
    private String firstName;
 
    private String surname;
 
    private String email;
 
    private byte[] avatar;
 
    private Date lastUpdated;
 
    @ApiModelProperty(position = 1, required = true, value = "username containing only lowercase letters or numbers")
    public String getUserName() {
        return userName;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    @ApiModelProperty(position = 2, required = true)
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    @ApiModelProperty(position = 3, required = true)
    public String getSurname() {
        return surname;
    }
 
    public void setSurname(String surname) {
        this.surname = surname;
    }
 
    @ApiModelProperty(position = 4, required = true)
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    @JsonIgnore
    public byte[] getAvatar() {
        return avatar;
    }
 
    public void setAvatar(byte[] avatar) {
        this.avatar = avatar;
    }
 
    @ApiModelProperty(position = 5, value = "timestamp of last modification")
    public Date getLastUpdated() {
        return lastUpdated;
    }
 
    public void setLastUpdated(Date lastUpdated) {
        this.lastUpdated = lastUpdated;
    }
}

Если вам нужно предоставить более подробную информацию о вашей модели, проверьте следующее описание @ApiModelProperty :

@ApiModelProperty аннотация

ApiModelProperty описывает свойство внутри класса модели. Аннотации могут применяться к методу, свойству и т. Д. В зависимости от конфигурации и использования сканера модели.

Параметры аннотации:

  • value – предоставить понятный человеку краткий обзор этого свойства
  • allowableValues – Если значения, которые можно установить, ограничены, они могут быть установлены здесь. В виде разделенного запятыми списка registered, active, closed
  • access – укажите необязательное значение доступа для фильтрации в реализации Filter . Это позволяет скрыть определенные параметры, если пользователь не имеет к ним доступа
  • notes – длинное описание имущества
  • dataType – тип данных. См. Документацию для поддерживаемых типов данных. Если тип данных является пользовательским объектом, задайте его имя или ничего. В случае перечисления используйте ‘string’ и allowableValues ​​для констант перечисления
  • requiredrequired ли свойство, по умолчанию установлено значение false
  • position – позволяет явно упорядочить свойство в модели. Поскольку рефлексия не гарантирует порядок, вы должны указать порядок свойств, чтобы модели оставались согласованными в разных реализациях и версиях виртуальных машин.

Если вы будете тщательно следовать этим инструкциям, у вас должна получиться полная документация по API в json по ранее упомянутому URL. Ниже приведена только часть, относящаяся к модели полученного json, теперь с предоставленной документацией

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
{
    ...
    "models":{ 
        "User":{ 
            "id":"User",
            "description":"",
            "required":[ 
                "userName",
                "firstName",
                "surname",
                "email"
            ],
            "properties":{ 
                "userName":{ 
                    "type":"string",
                    "description":"username containing only lowercase letters or numbers"
                },
                "firstName":{ 
                    "type":"string"
                },
                "surname":{ 
                    "type":"string"
                },
                "email":{ 
                    "type":"string"
                },
                "lastUpdated":{ 
                    "type":"string",
                    "format":"date-time",
                    "description":"timestamp of last modification"
                }
            }
        }
    }
}

Что дальше?

Если вы выполнили все шаги, у вас должна быть рабочая документация API, которая может быть опубликована или дополнительно обработана средствами автоматизации. Я продемонстрирую, как представить документацию по API с помощью модуля Swagger UI, в моей следующей статье под названием Spring Rest API with Swagger – Предоставление документации. Код, используемый в этой микросерии, опубликован на GitHub и содержит примеры для всех обсуждаемых функций и инструментов. Пожалуйста, наслаждайтесь!

Ссылка: Spring Rest API с Swagger – Создание документации от нашего партнера JCG Якуба Стаса в блоге