Je suis en train de construire un service Web REST en Java avec Spring, Jersey et Hibernate (JPA).
J'essaie maintenant d'ajouter un support pour la validation dans mes ressources. JSR-303 (validation de haricot) est naturellement apparu comme un choix approprié (j'utilise Hibernate Validator, qui est l'implémentation de référence de JSR-303). Cependant, j'essaie d'abord de consolider certains concepts.
Il me semble qu’il existe au moins deux types de validations possibles:
String
est un courrier électronique valide, vérifiez si une propriété Integer
est supérieure à 10
, etc. Cela fonctionne comme prévu. J'ai enregistré un ExceptionMapper JAX-RS qui mappe les javax.validation.ConstraintViolationException
dans les réponses HTTP appropriées.Je vais expliquer ce que je veux dire exactement par "Validation de l'intégrité des données" avec un exemple. Cela se produit lorsqu'il existe des relations entre deux ressources ou plus. Imaginez deux ressources: une Product
et une Category
. Une Product
a une Category
. Lorsque le client envoie au serveur la représentation de la Product
à créer (une requête HTTP POST), il doit informer la Category
du produit. Le client doit bien sûr connaître les catégories à l’avance. Imaginez dans JSON quelque chose comme:
{
"quantity": "10",
"state": "PRODUCED",
"category": {
"id": "123"
}
}
Eh bien, la catégorie avec id 123
pourrait ne pas exister. Si nous essayons d'insérer ceci dans la base de données, nous obtenons évidemment une exception liée à la clé étrangère. Je suppose donc que nous devons valider ces problèmes et renvoyer un message approprié au client, tout comme dans les validations de propriété normales.
Maintenant, mes questions principales sont:
Ces questions sont un peu liées à Java, mais j’espérais aussi avoir de nouvelles perspectives sur ces questions. Certains indépendants de la technologie. :) Ce serait formidable si vous pouviez apporter vos propres solutions à ces problèmes sur vos services Web REST.
La solution a fini par sous-classer le JacksonJaxbJsonProvider
de Jackson qui implémente un JAX-RS MessageBodyReader
et MessageBodyWriter
. J'ai été inspiré par la surprenante approche de dropwizard . Dans ce fournisseur, nous devons en quelque sorte injecter une instance de Validateur (j'ai utilisé Spring pour Injection et Hibernate Validator pour l'implémentation JSR-303). Si vous utilisez Hibernate ORM, n'oubliez pas de désactiver la validation d'entité, sinon vous validerez la même entité deux fois. Ce peut être ce qui est désiré, cependant.
Ensuite, dans cette sous-classe MessageBodyReader
, je valide l'objet et jette un nom personnalisé InvalidEntityException
avec les erreurs du validateur. J'ai également créé un ExceptionMapper<InvalidEntityException>
JAX-RS qui mappe chaque InvalidEntityException
en une réponse HTTP appropriée. Dans mon cas, j'ai renvoyé une requête incorrecte et un objet JSON contenant la description des erreurs.
Notez que ce MessageBodyReader vérifie les annotations @Valid
et @Validated
. Cela signifie qu'il prend correctement en charge les groupes. Ceci est important car nous ne voulons probablement pas faire le même type de validation sur l’ensemble de notre application. Un exemple est lorsque nous voulons faire une mise à jour partielle (PUT). Ou, par exemple, une propriété id doit être null dans une demande POST mais non nulle partout ailleurs.
Intégrité des données Les validations ne sont pas encore complètement traitées. Mais je prévois attraper les exceptions de base de données et les convertir en mes propres exceptions de domaine (disons un DataIntegrityException
) car cela me semble plus efficace et plus ou moins couplé.
METTRE À JOUR:
Depuis JAX-RS 2, la méthode recommandée consiste à utiliser le support de validation de bean. Vérifiez ici: https://jersey.Java.net/documentation/latest/bean-validation.html
Vous pouvez maintenant utiliser Jersey 2.0 pour la validation des arguments de ressources via JSR-303/JSR-349.
https://jersey.Java.net/documentation/latest/bean-validation.html#d0e9301
Vous pouvez utiliser jersey filters
, où vous pouvez effectuer des validations sur les données de votre demande.
Eh bien, la catégorie avec l'ID 123 pourrait ne pas exister. Si nous essayons d'insérer ceci dans la base de données, nous obtiendrons évidemment une exception liée à la clé étrangère.
Dans ce cas, on peut s’appuyer sur les validations au niveau d’accès aux données. Toutefois, si vous souhaitez répondre à votre client de manière synchrone, il est généralement préférable d'exposer cette logique métier à l'aide d'une API de service. Par exemple, vous pouvez avoir une API telle que isValidCategory(int id)
, qui peut être interrogée à un niveau supérieur à celui de DAO afin de ne pas avoir à attendre que la couche d'accès aux données rencontre une erreur/une exception. Évidemment, cela peut toujours signifier une consultation de base de données (dépend de votre système), mais l'optimisation de cette opération pour améliorer votre temps de réponse à l'aide de la mise en cache ou d'un autre mécanisme est un problème totalement différent.
En parlant de validateurs de beans, vous pouvez jeter un oeil à Hibernate Validator qui est une implémentation JSR 303.
Ovale est le meilleur package pour évaluer un objet. Il est très utile de générer une assertion de test unitaire et un test automatisé.