Как обрабатывать проверку ресурсов в веб-службах REST?
Я создаю веб-сервис REST на Java с помощью Spring, Jersey и Hibernate (JPA).
Теперь я пытаюсь добавить поддержку для проверки в моих ресурсах. JSR-303 (Bean validation), естественно, явился подходящим выбором (я использую Hibernate Validator, который является эталонной реализацией JSR-303). Тем не менее, я сначала пытаюсь объединить некоторые концепции.
Мне кажется, что существует как минимум два вида возможных валидаций:
- Регулярная проверка в полях, например. убедитесь, что свойство не равно null, проверьте, является ли свойство
String
допустимым адресом электронной почты, проверьте, превышает ли свойство Integer
10
и т.д. Это работает как ожидалось. Я зарегистрировал JAX-RS ExceptionMapper, который отображает javax.validation.ConstraintViolationException
в соответствующие ответы HTTP.
- Проверка целостности данных
Я объясню, что я имею в виду именно "Проверка целостности данных" с примером. Это происходит, когда есть отношения между двумя или более ресурсами. Представьте себе два ресурса: a Product
и a Category
. A Product
имеет a Category
. Когда клиент отправляет серверу представление Product
для создания (HTTP-запрос POST), он должен сообщить Category
о продукте. Конечно, клиент должен знать категории заранее. Представьте себе в JSON что-то вроде:
{
"quantity": "10",
"state": "PRODUCED",
"category": {
"id": "123"
}
}
Ну, категория с id 123
может не существовать. Если мы попытаемся вставить это в базу данных, очевидно, мы получим исключение, связанное с внешним ключом. Поэтому я предполагаю, что мы должны проверить эти проблемы и вернуть правильное сообщение клиенту, так же как и в регулярных проверках свойств.
Теперь мои основные вопросы:
- Сейчас я выполняю проверку на уровне доступа к данным через интеграцию JPA с помощью Bean Validation. Если проверки выполняются до/после процессов сериализации, до/после операций с базой данных или и?
- Как обрабатывать проверки целостности данных? Вручную? (т.е. явно консультироваться с проверкой целостности данных базы данных). Или мы должны просто попытаться вставить его в любом случае, а затем уловить исключения базы данных (или DAO)? Bean Валидация не имеет ничего общего с такой проверкой, правильно?
- Если у вас есть опыт работы с JAX-RS/REST и Bean Validation, я был бы рад, если вы дадите мне знать. Использование групп?
Эти вопросы несколько связаны с Java, но я также надеялся получить некоторые новые перспективы по этим вопросам. Некоторые технологически независимые.:)
Было бы здорово, если бы вы могли предоставить свои собственные решения для этих проблем на веб-сервисах REST.
Ответы
Ответ 1
Решение оказалось подклассом Jackson JacksonJaxbJsonProvider
, в котором реализованы JAX-RS MessageBodyReader
и MessageBodyWriter
.
Я был вдохновлен удивительным подходом dropwizard. В этом провайдере нам нужно каким-то образом внедрить экземпляр Validator (я использовал Spring для Injection и Hibernate Validator для реализации JSR-303). Если вы используете Hibernate ORM, не забудьте отключить проверку объекта, иначе вы будете дважды проверять один и тот же объект. Однако это может быть желательным.
Затем в этом подклассе MessageBodyReader
я проверяю объект и вывожу пользовательский InvalidEntityException
с ошибками из проверки. Я также создал JAX-RS ExceptionMapper<InvalidEntityException>
, который отображает каждый InvalidEntityException
в правильный HTTP-ответ. В моем случае я вернул Bad Request и JSON-объект, содержащий описание ошибок.
Обратите внимание, что этот MessageBodyReader проверяет аннотации @Valid
и @Validated
. Это означает, что он правильно поддерживает группы. Это важно, потому что мы, вероятно, не хотим выполнять такую же проверку во всем нашем приложении. Например, мы хотим сделать частичное обновление (PUT). Или, например, свойство id должно быть нулевым в запросе POST, но не нулевым везде.
Проверка целостности данных еще не решена. Но я планирую ловить исключения баз данных и преобразовывать их в свои собственные исключения для домена (например, < <29 > ), поскольку он кажется более эффективным и слабо связанным со мной.
UPDATE:
Так как JAX-RS 2, рекомендуемый способ сделать это - использовать поддержку Bean Validation. Проверьте здесь: https://jersey.java.net/documentation/latest/bean-validation.html
Ответ 2
Теперь вы можете использовать Джерси 2.0 для проверки аргументов ресурсов через JSR-303/JSR-349.
https://jersey.java.net/documentation/latest/bean-validation.html#d0e9301
Ответ 3
Вы можете использовать jersey filters
, где вы можете сделать некоторые проверки в своих данных запроса.
Ну, категория с id 123 может не существовать. Если мы попытаемся вставить это в базу данных, очевидно, мы получим исключение, связанное с внешним ключом.
В таких случаях можно полагаться на проверки на уровне доступа к данным. Но если вы хотите синхронно реагировать на ваш клиент, обычно лучше иметь эту бизнес-логику, предоставляемую некоторым сервисным API. т.е. у вас может быть API, например isValidCategory(int id)
, который может запрашиваться на более высоком уровне, чем DAO, так что вам не нужно ждать, пока уровень доступа к данным столкнется с ошибкой/исключением. Очевидно, что это все равно означает поиск базы данных (зависит от вашей системы), но оптимизация этого для улучшения времени отклика с использованием кеширования или какого-либо другого механизма - совсем другая проблема.
Говоря о валидаторах bean, вы можете посмотреть Hibernate Validator, который является реализацией JSR 303.
Ответ 4
Oval - лучший пакет для оценки объекта. Очень полезно генерировать утверждение unit test и автоматическое тестирование.