Мне действительно нравится разработка API . Как человек, который любит писать, я также с удовольствием предоставляю исчерпывающую документацию для пользователей моих API. Когда мои API используются командами в Соединенных Штатах и других странах, становится важно предоставлять надежную и подробную информацию. То же самое верно для публичных API, когда потребитель просто не известен.
Тем не менее, я действительно не фанат повторения в моем коде … и это включает в себя документацию API.
Когда наша команда столкнулась с проблемой SpringFox и SpringBoot версии 2.2.x, я решил перейти от использования SpringFox к springdoc-openapi для нашей документации по API. Увидев множество повторяющихся элементов в аннотациях SpringFox от одного метода контроллера к другому, я решил выяснить, как применять принцип СУХОЙ (не повторяйся) в документации OpenAPI, которую мы будем использовать с помощью Swagger.
Вам также могут понравиться:
Принципы разработки программного обеспечения DRY и KISS
Общий пример
Рассмотрим следующий пример контроллера:
Джава
1
summary = "For a given accountId, return a list of orders.") (
2
value = { (
3
responseCode = "200", description = "ok"), (
4
responseCode = "400", description = "request could not be processed"), (
5
responseCode = "401", description = "user account is not valid", content = ()), (
6
responseCode = "403", description = "user does not have access to perform this request", content = ()) (
7
})
8
value = "account/{accountId}/orders") (
9
public ResponseEntity<List<Order>> getOrders( Long accountId) {
10
try {
11
return new ResponseEntity<>(orderService.getOrders(accountId), HttpStatus.OK);
12
} catch (OrderException e) {
13
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
14
}
15
}
Существуют некоторые аннотации, используемые для сбора данных для пользовательского интерфейса Swagger.
Возможно, вы заметили, что контроллер выдает ответ BAD_REQUEST, но Swagger также учитывает ответы UNAUTHORIZED и FORBIDDEN. Они будут выброшены из перехватчика безопасности. Если вы хотите увидеть пример, просто просмотрите следующую статью, которую я опубликовал в прошлом месяце:
Использование @RequestScope с вашим API
Хотя информация в приведенном выше примере даст очень хорошую документацию, после пары API-интерфейсов будет легко понять, что в тексте аннотации много дублирования. Это было бы не так сухо, если вы спросите меня.
Должен быть лучший способ сделать это.
Введите аннотации
Начиная с версии 5 Java, разработчики могли создавать и использовать аннотации, чтобы сделать их жизнь проще. Поэтому, безусловно, должен быть способ использовать аннотацию, чтобы не повторяться на каждом контроллере, который я выставляю Swagger.
Оказывается, это было довольно просто. Рассмотрим следующий пример для НЕСАНКЦИОНИРОВАННОЙ и ЗАПРЕЩЕННОЙ документации:
Джава
xxxxxxxxxx
1
RetentionPolicy.RUNTIME) (
2
ElementType.METHOD) (
3
value = { (
4
responseCode = Constants.UNAUTHORIZED, description = "request could not be processed", content = ()), (
5
responseCode = Constants.FORBIDDEN, description = "user account is not valid", content = ()) (
6
})
7
public @interface ApiAuthResponses { }
Теперь я могу просто включить @ApiAuthResponses в свой контроллер, чтобы включить эти два ответа. Это означает, что контент находится в одном месте, поэтому, если мы решим изменить текст, изменения должны быть сделаны только один раз.
Кроме того, я продолжил и установил константы для всех наших основных значений responseCode и description:
Джава
xxxxxxxxxx
1
public static final String OK = "200";
2
public static final String CREATED = "201";
3
public static final String ACCEPTED = "202";
4
public static final String NO_CONTENT = "204";
5
public static final String BAD_REQUEST = "400";
6
public static final String UNAUTHORIZED = "401";
7
public static final String FORBIDDEN = "403";
8
public static final String NOT_FOUND = "404";
9
public static final String METHOD_NOT_ALLOWED = "405";
10
public static final String CONFLICT = "409";
11
public static final String UNPROCESSABLE = "422";
12
public static final String INTERNAL_SERVER_ERROR = "500";
13
14
public static final String ACCEPTED_TEXT = "accepted";
15
public static final String CREATED_TEXT = "created";
16
public static final String NO_CONTENT_TEXT = "no content";
17
public static final String OK_TEXT = "ok";
Обновленный контроллер
При наличии интерфейса и констант обновленный контроллер выглядит следующим образом:
Джава
xxxxxxxxxx
1
summary = "For a given accountId, return a list of orders.") (
2
value = { (
3
responseCode = Constants.OK, description = Constants.OK_TEXT), (
4
responseCode = Constants.BAD_REQUEST, description = "request could not be processed") (
5
})
6
7
value = "account/{accountId}/orders") (
8
public ResponseEntity<List<Order>> getOrders( Long accountId) {
9
try {
10
return new ResponseEntity<>(orderService.getOrders(accountId), HttpStatus.OK);
11
} catch (OrderException e) {
12
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
13
}
14
}
Теперь документация для URI getOrders () содержит только информацию, которая применима для этого метода контроллера. Общие коды откликов и описания были перемещены в класс констант. Документация для распространенных исключений была помещена в класс ApiAuthResponses.
В результате моя документация по OpenAPI именно такая, какая мне нравится … полезная и довольно СУХАЯ.
Хорошего дня!