Jednym z ważnych elementów warstwy REST-owej aplikacji jest walidacja żądań, które przychodzą. Możemy osiągnąć to w łatwy sposób dzięki adnotacji z pakietu javax.validation.constraints
dla pojedynczych atrybutów.
Co jeżeli chcemy zwalidować grupę parametrów?
ConstraintValidator #
To, czego potrzebujemy użyć, to ConstraintValidator
. Z jego pomocą jesteśmy w stanie zbadać całą zawartość obiektu i poinstruować warstwę API serwisu, czy wszystko jest w porządku.
W tym celu potrzebujemy do zależności dodać hibernate-validator
.
org.hibernate
hibernate-validator
6.1.5.Final
Oraz zdefiniować kontroler REST-owy.
@RestController
@RequestMapping("/orders")
class
OrderController
{
@PostMapping
public
ResponseEntity<Object>
makeAnOrder(@RequestBody
@Valid
OrderRequest
orderRequest,
Errors
errors)
{
if(errors.hasErrors())
{
return
errorResponse(errors);
}
log.info("Faking order for: "
+
orderRequest);
return
ResponseEntity.ok("It's fine!");
}
}
Zauważ, iż OrderRequest
posiada standardową adnotację @Valid
.
Jak ona działa?
Walidacja obiektu #
Do walidacji całego obiektu potrzebujemy trzech elementów:
- samego obiektu :)
- adnotacji, którą oznaczymy obiekt do walidacji,
- implementacji
ConstraintValidator
.
Po kolei.
Klasa obiektu może wyglądać tak:
@OrderRequestValid
public
record
OrderRequest(String
name,
boolean
invoice,
String
vatNumber)
{
}
Adnotacja:
@Target({TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy
=
OrderRequestValidator.class)
@Documented
@interface
OrderRequestValid
{
String
message()
default
"Missing VAT number while requesting for an invoice";
Class>[]
groups()
default
{};
Class
extends
Payload>[]
payload()
default
{};
}
Oraz nasz Validator
:
class
OrderRequestValidator
implements
ConstraintValidator<OrderRequestValid,
OrderRequest>
{
@Override
public
boolean
isValid(OrderRequest
request,
ConstraintValidatorContext
constraintValidatorContext)
{
if
(request.invoice()
&&
StringUtils.isBlank(request.vatNumber()))
{
return
false;
}
return
true;
}
}
I to wszystko #
Całość zadzieje się już sama.
Dzięki obecności @Valid
w kontrolerze poprosimy Springa by sprawdził poprawność obiektu.
Obecność kolejnej adnotacji @OrderRequestValid
na obiekcie uruchomi logikę powiązaną ze wskazanymi w definicji adnotacji walidatorem.
@Constraint(validatedBy
=
OrderRequestValidator.class)
Na końcu odpali się metoda z walidatora, którą możemy dowolnie zaimplementować, tak by spełniała nasze wymagania.
@Override
public
boolean
isValid(OrderRequest
request,
ConstraintValidatorContext
constraintValidatorContext)
{
if
(request.invoice()
&&
StringUtils.isBlank(request.vatNumber()))
{
return
false;
}
return
true;
}
Podsumowanie #
W ten sposób możemy przygotować własną logikę dotyczącą zestawu atrybutów, które chcemy walidować podczas przyjmowania żądań do naszego REST API.
PS. jeżeli chcesz otrzywać dostęp do całego kodu źródłowego, zapisz się na newsletter poniżej a otrzymasz go jako bonus :)