Извлечение сложных данных
#
Васильев Андрей Михайлович, 2024
Версии презентации
Добавление собственных сообщений об ошибках
#
Линзы в http4k предоставляют большой набор методов для преобразования строковых
значений в стандартные типы: числа, непустые строки, UUID, даты и т.д.
В рамках приложения бывает недостаточно просто преобразовать данные, нужно
дополнять дополнительными ограничениями:
- Нужно только положительное целое число
- Идентификатор должен соответствовать реально существующему элементу
Для решения такой задачи спецификации линз можно уточнить с помощью функции map
Варианты функции map
#
Двусторонняя спецификация линзы предоставляет 3 варианта данной функции
Первый вариант функции map
принимает в качестве аргумента 2 функции:
- Функция для преобразования из входного типа в выходной
- Функция для преобразования из выходного во входной тип
Результат вызова данной функции — двусторонняя линза
Второй вариант функции map
принимает в качестве аргумента 1 функцию:
- Функцию для преобразования из входного типа в выходной
Результат вызова данной функции — односторонняя линза
Третий вариант функции map
принимает в качестве аргумента объект типа
BiDiMapping
Создание двусторонней линзы для положительных целых чисел
#
- Воспользуемся первой формой функции
map
- В случае проблем с данными будем выбрасывать исключение LensFailure
val positiveIntLens = Query.int().map(
{ number ->
if (number <= 1) {
throw LensFailure(
message = "Параметр number должен быть положительным"
)
}
number
},
{ number -> number },
).defaulted("number", 1)
- Первая функция принимает целое число и добавляет проверку данных
- Вторая функция обеспечивает обратное преобразование целого числа в целое
число
- Название поле указывается дважды: в терминаторе и сообщении об ошибке
- В качестве альтернативы можно выбросить IllegalArgumentException, но тогда
сообщение будет стандартизировано
- Линзу можно использовать как для чтения, так и для записи
Введение собственных типов для линз
#
Накладывание дополнительных ограничений на ввод де-факто создаёт новый тип
данных, который может использоваться несколько раз
Для создания подобного рода линз есть два пути:
- Создать собственную базовую спецификацию линзы
- Вынести логику по преобразованию данных в объект BiDiMapping
val positiveIntMapping = BiDiMapping(
{ number: Int ->
if (number <= 1) {
throw IllegalArgumentException("Поле должно быть положительным")
}
number
},
{ number: Int -> number },
)
val positiveIntLens = Query.int().map(positiveIntMapping)
.defaulted("number", 1)
Внутри BiDiMapping невозможно создать сообщение с указанием названия поля
Создание объединённых параметров запроса
#
Зачастую параметры, которые приходят от пользователя не являются независимыми и
их было бы удобно обрабатывать как единую логическую единицу
Примером такого набора данных могут служить параметры постраничного вывода
Для объединения нескольких линз можно воспользоваться функцией composite
data class Pageable(val sortAscending: Boolean, val page: Int,
val maxResults: Int)
val pageableLens = Query.composite { request ->
Pageable(
boolean().defaulted("sortAscending", true)(request),
int().defaulted("page", 1)(request),
int().defaulted("maxResults", 20)(request)
)
}
val pageable: Pageable = pageableLens(request)
- Можно объединять только линзы, работающие с одним источником: путём запроса,
параметры запроса, заголовки и т.д.
- Только первая ошибка будет выведена пользователю