Kotlin Spring Request Blank Validation Best Practice - spring

I'm new to kotlin and so far I have 2 options to do not blank validation on incoming HTTP request since a blank string considered as valid value in kotlin null checking.
Validation on class init function
data class Foo(val key: String) {
init {if (this.key.isEmpty()) throw Exception("Invalid Request")}
}
Validation with javax annotation
data class Foo(#field.NotBlank val key: String)
Both ways are working as expected, I just curious on what's the best way to do this in kotlin. I'm afraid that my kotlin code is to java, at that point no use I work with kotlin

If you want to validate the incoming request, go for 2nd option.
Consider having more than one attribute, lets say you have class such as:
data class User(val name: String, val surname:String)
Then you have to write validation for each field. What if both name and surname are blank? The name validation throws an error, you add name to request and BAM, surname validation throws an error.
data class User(val name: String, val surname:String) {
init {
if (this.name.isEmpty()) throw Exception("Name is missing")
if (this.surname.isEmpty()) throw Exception("Surname is missing)
}
}
You can validate all at once, using OR for example, but then you would lose explicit error - what was wrong? Blank name? Blank surname? Both were blank...?
data class User(val name: String, val surname:String) {
init {
if (this.name.isEmpty() || this.surname.isEmpty()) throw Exception("Name or surname is missing")
}
}
Now think about three, four, five fields.
If you use javax.validation properly, you have to write just the annotations and the rest is done by the framework - it will explictly say, what is wrong, on which field, because it checks all the constraints and if there are any violations, it throws an error with all violation details.

Related

Validate URL Parameters in an Openapi 3.0 Spring Boot RESTful API?

In my openapi spec I specify URL parameters for a specific resource path like so:
paths:
/some/path:
get:
summary: some summary
parameters:
name: usefulParameter
description:
schema:
type: string
maxLength: 15
Using openapi 3.0 codegen I generate a Spring Boot RESTful API which automatically generates an interface with a name like xxxxDelegate, which has methods that must be implemented like:
default ResponseEntity<Object> somePathGet(String usefulParameter) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
String exampleString = "null";
ApiUtil.setExampleResponse(request, "application/json", exampleString);
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
Which has a comment at the top of the interface stating:
A delegate to be called by the {#link YourApiController}}.
Implement this interface with a {#link org.springframework.stereotype.Service} annotated class.
So I do exactly that, which results in my own class which looks like this:
#Service
public class MyCustomClass implements xxxxDelegate {
#Override
public ResponseEntity<Object> somePathGet(String usefulParameter) {
}
}
So far this works perfectly. I can invoke it and log the input parameter. The issue that I'm having is that I can't seem to find documentation anywhere on how to assign validation to that input parameter - the Openapi 'maxLength' is not being applied, and Spring/Spring Boot doesn't seem to provide a way to apply validation to these parameters unless you use Model type classes and annotate the members. I would prefer to avoid that and instead simply tell the API that this URL parameter requires specific validation, such as min/max length, or a certain character set.
Is this possible?
You can use
x-field-extra-annotation: "#Email"
in field definitions of the api-defining yaml. Self-defined validators are possible if you put them into the org.openapitools.model package.
In the server-side API-implementation you need to put the #Valid annotation in front of any parameter you want to have validated.
Here is an example for an UUID scheme with custom validation (note that the validation rules defined in the yaml have no effect on the generated Spring-Java-Code):
schemas:
UUID:
description: "Format: UUID"
type: "string"
pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
minLength: 36
maxLength: 36
example: "097c9a34-ec4c-4766-b29b-f528db4a3ef8"
x-field-extra-annotation: "#UUID"

Deserialize nested Kotlin object in springMVC

I'm trying to deserialize a complex GET request into a structure of nested objects.
The GET requests looks like:
curl 'localhost:8080/?id=1&inner.id=1'
and the code should look like this:
class RootObj(val id: Int, inner: InnerObject)
class InnerObject(val id: Int)
#RestController
class SearchController {
#GetMapping(path = ["/"])
fun getRoot(rootObj: RootObj): String {
return "ok"
}
}
This doesn't work out of the box I guess because spring doesn't know how properly create this nested structure.
Parameter specified as non-null is null: [...] parameter inner","path":"/"}%
Is there a way to overcome this problem? Maybe providing a totally custom deserializer code?
As alternative solution, I guess I could flatten the object hierarchy but for doing so I must be able to map a query parameter like inner.id to a field named innerId
Spring can actually map the query params to the custom object directly, but you need to provide defaults to the params of the custom object constructor.
So you need to define your classes as below for it to work
class RootObj(val id: Int = 0, val inner: InnerObject = InnerObject(0))
class InnerObject(var id: Int = 0)
Do note that the id field of InnerObject would have to be declared as var for Spring to be able to map it. Then curl 'localhost:8080/?id=1&inner.id=1' would work fine.

How to validate RequestBody with nullable fields when all properties are empty/null values

I would like to know if there is a better way then writting a check at the beginning of a method.
This question is based on the following code:
Class Pojo:
data class PojoX(val name: String?, val city: String?)
Controller:
#PatchMapping("/demo")
fun update(#RequestBody request: PojoX): PojoDTO{
if (request.name == null && request.city == null) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Atleast one field should be filled")
}
// Do somthing if atleast one field is filled...
}
I want the code to be maintainable easily without adding new check when a new property is added to the request class.
Is there an annotation in Spring which can check if all fields are null?
You'd need to write a custom Validator that is only valid if at least one of the fields is not null (i.e. encapsulating your current check into a validator and then use the #Valid annotation.

How to validate a single field in a Spring bean?

It seems like the preferred way to validate a spring annotated bean is by using #valid, like in the block below, however I want to display error messages one field at a time still using Spring annotations. I know I can validate the whole form after each field and show only messages for a single field, but that is inefficient, anyone know of a better way?
#RequestMapping(value="/register",method=RequestMethod.POST)
public #ResponseBody RegisterResponse registerSubmit(#Valid #ModelAttribute("registerData") Register registerData, BindingResult result ){
RegisterResponse rr= new RegisterResponse();
if(!result.hasErrors()) {
rr.setStatus("SUCCESS");
rr.setResult(result);
}
else {
rr.setStatus("FAIL");
rr.setResult(result.getAllErrors());
}
return rr;
}
Return from the Validator#validate method upon hitting the first Error.
For this
You need to have a Custom Validator implementing org.springframework.validation.Validator where you have control of validating the fields in the order you need, whereas, using #Valid annotation will validate all the fields in your Form Bean and return the BindingResult for all the fields.
I was able to make things work by filtering out the errors that had an empty/null fields, this does work but is a bit inefficient since we validate entire bean even though we care for the first field. I'd love to hear of a better way to accomplish this kind of step by step form field validation.
I used something like the following:
private List<ObjectError> removeEmpties(BindingResult result) {
List<ObjectError> errors = result.getAllErrors();
ArrayList<ObjectError> myErrors = new ArrayList<ObjectError>();
for(ObjectError error: errors){
FieldError realThing = (FieldError) error;
if (realThing.getRejectedValue()!=null && !realThing.getRejectedValue().toString().isEmpty()){
myErrors.add(error);
}
}
return myErrors;
}

Groovy validation problem

I have a groovy system configured using tomcat and Oracle 10g.
I have a groovy class which defines an follows: (reduced version)
class ChangeTicket {
static constraints = {
chngNr(nullable:false)
}
String chngNr
}
My controller has defined a save method:
if (changeTicketInstance.validate() && !changeTicketInstance.hasErrors() && changeTicketInstance.save()) {
flash.message = "changeTicket.created"
...
}
As far as I know the save method calls by default the validate method in order to
know if the constraints are fullfilled or not therefore the validate method call is redundant. Anyway, when the save is performed an exception will be thrown if the field chngNr is NULL.
In fact the field cannot be empty (NULL) because I've defined the constraint (nullable:false).
What am I doing wrong here?
Thanks in advance,
Luis
The validate call should fail if chngNr is NULL. Some databases do not consider an empty string ("") null (HSQL). If you are binding chngNr to changeTicketInstance using params from a form it is getting assigned an empty string as a value and in that case you would want your constraint to be:
chngNr(blank:false)
Also, save() wont throw an Exception unless you use save(flush:true). Hibernate queues up the changes and, unless you flush, wont throw an actual exception.
try this:
chngName(blank:false,nullable:false)
:-)

Resources