Grails: How do a validate POST body consisting of a list of items using a command object?

242 Views Asked by At

I am facing some issues with writing custom validators (Commands) in grails 3.3.3. Specifically, I am trying to validate POST request whose body is composed of a list of items. This is what I have...

The Command:

class VoteCommand implements Validateable {


    List<VoteItem> postList = [].withLazyDefault { new ListItem() }

    static constraints = {
        postList nullable: false
    }

    class ListItem implements Validateable {
        String tag
        String some_id

        static constraints = {
            some_id nullable: false, blank: false
            tag nullable: false, blank: false
            tag inList: Tag.values() as List
        }
    }
}

AND the Payload:

{
    "noteVotesButWorks": [

                {
                    "tag": "good"
                },
                {
                    "tag": "bad"
                }
        ]
}

This payload passes the validation check in my controller action.

 def save(VoteCommand command) {


            println(command.errors) //grails.validation.ValidationErrors: 0 errors



            if (command.hasErrors()) {
                respond params.errors, view: 'create'
            } else {
                withFormat {
                    '*' { render status: CREATED }
                }
            }

}

After making the POST request to this action, I get a 201 and grails.validation.ValidationErrors: 0 errors printed to stdout.

Please, can someone here give me some pointers?

2

There are 2 best solutions below

2
Daniel On

I don't think you want nullable: false for postList. An empty list is not null. I think you want minSize: 1.

0
Jeff Scott Brown On

Please, can someone here give me some pointers?

Your payload includes the key noteVotesButWorks. The data binder is going to create an instance of VoteCommand and then look to see if there is a noteVotesButWorks property on that instance, and there isn't, so the data binder doesn't really have anything to do. Your VoteCommand instance is then validated, which passes because your only constraint is postList nullable: false, which passes because postList is not null.

That all is working as designed. You probably want the key in your payload map to match the name of the List property in VoteCommand.

Separate from all of that, there is no good reason to include .withLazyDefault { new ListItem() } in your property initialization. You don't really have to initialize the property at all. The data binder will do that for you.