На смену springfox пришел springdoc. Он приносит нам в проект Swagger и поддерживает спецификацию OpenApi 3. Но есть еще некоторые шерховатости, а именно правильное отображение параметров запроса для сортировки и постраничного вывода.
Давайте посмотрим, можно ли их исправить и как это сделать.
Проблема
После добавления в проект артефакта springdoc-openapi-ui становится доступна страница http://localhost:8080/swagger-ui.html
Все красиво и аккуратно кроме параметров типа Pageable
и Sort
.
@GetMapping("/sort")
public @ResponseBody void sort(Sort sort) {
//
}
@GetMapping("/pageable")
public @ResponseBody void pageable(Pageable pageable) {
//
}
Описание Pageable
только выглядит странно, но пользоваться им можно.
Объект:
{
"page": 0,
"size": 1,
"sort": [
"string"
]
}
будет преобразован в набор параметров строки запроса:
curl -X 'GET'
'http://localhost:8080/pageable?page=0&size=1&sort=string'
-H 'accept: /'
А вот описание для Sort
не соответствует действительности. Нам нужен параметр строки запроса sort, а не вот это:
К тому же в этих объектах параметрах нет описаний.
Устранение
Для Pageable
все просто. Достаточно перед параметром метода аннотацию @ParameterObject
@GetMapping("/pageable")
public @ResponseBody void pageable(@ParameterObject Pageable pageable) {
//
}
Красивое...
Для Sort
так сделать не получится. Но выход есть:
Скрываем настоящий параметр с помощью аннотации
@Parameter(hidden = true)
;Описываем правильный параметр самостоятельно.
Получается следующая конструкция:
@Parameter(in = ParameterIn.QUERY,
description = "Sorting criteria in the format: property(,asc|desc). " +
"Default sort order is ascending. " +
"Multiple sort criteria are supported.",
name = "sort",
required = false,
array = @ArraySchema(schema = @Schema(type = "string")))
@GetMapping("/sort")
public @ResponseBody void sort(@Parameter(hidden = true) Sort sort) {
//
}
Теперь все выглядит так, как и задумывалось. Swagger можно использовать, а спецификацию OpenApi отдавать FrontEnd-разработчикам.
Надеюсь, что в скором времени для Sort
тоже можно будет использовать аннотацию @ParameterObject
.
Bromles
При использовании этого решения натыкался на проблему: при наличии в контроллере более одного маппинга на один и тот же адрес, но с разными параметрами, в Сваггере в итоге все эти маппинги превращались в один эндпоинт, описание, схема и прочее которого случайно бралось от одного из маппингов, а в параметрах были абсолютно все параметры из всех маппингов по этому адресу, и с пометкой required (даже если в самих маппингах явно стоит required = false)
Судя по всему, он просто мержит все эндпоинты на основании их адреса, а не методов с маппингами. В итоге вместо нескольких нормальных маппингов получается один, в который навалено все подряд в случайном порядке, да еще и вводящие в заблуждение параметры указаны
Есть ли какой-то способ это починить?
semo Автор
Есть ссылка на гит* ? Без примеров кода сложно представить конструкцию.
Не обещаю что починю, но посмотрю обязательно :)
Bromles
Я чуть ниже запостил код, если что-то еще понадобится - обращайтесь)
Bromles
То есть, код следующего вида:
Превращается в такой вот эндпоинт:
semo Автор
Все верно. С точки зрения REST и OpenApi - это и есть один эндпоинт, так как имеет общий uri.
Посмотрите спецификацию. Все начинается с path. Попробуйте сформулировать свое желание сначала в виде спецификации https://editor.swagger.io/ а потом сгенерировать код.
Я вижу интересный вариант по разнесению одного эндпоинта за счет применения
params
, но тогда для того чтобы это работало нужно:1. Указать параметры для спецификации как 'required = false'
2. Предусмотреть вариант когда пользователь не ввел никаких параметров "поиска". Наверняка в вашем контроллере есть что-то типа getAll() без параметров и он тоже попал в этот эндпоинт.
Я бы предложил пересмотреть подход и вместо вызова отдельных методов репозитория использовать спецификации и один энпоинт `/search`