grails-core icon indicating copy to clipboard operation
grails-core copied to clipboard

Grails 3.1.1 - command object data binding does not play well with UrlMappings params

Open AleksanderGrzybowski opened this issue 9 years ago • 9 comments
trafficstars

I have an issue regarding data binding from JSON body to command object. I can provide sample app, but for now here are relevant snippets

"/api/someEndpoint/$id?"(controller: 'book', action: 'index', method: 'POST')
class BookController {
    def index(SomeCommandObject cmd) {
        render ([paramsAre: params, commandIs: cmd] as JSON)
    }
}

class SomeCommandObject {
    Long id
    String someString
    Integer someInteger
}

When POST-ing empty request to :8080/api/someEndpoint/1 the 'id' field of a command object is bound correctly, however including JSON, like this (using httpie)

http POST :8080/api/someEndpoint/1 someString=abc

causes 'someString' to bind but 'id' is null. I would expect these two sources of data (body and params coming from UrlMappings) to be merged. This issue seems relevant https://jira.grails.org/browse/GRAILS-11263

AleksanderGrzybowski avatar Feb 16 '16 13:02 AleksanderGrzybowski

This has come up before, multiple times.. the consensus seems to be that binding the body and params are separate things. Maybe @jeffbrown can comment.

graemerocher avatar Feb 18 '16 08:02 graemerocher

Just one comment from me - changing this now would may be breaking change. There is question of what should have priority in case of the same param in both sources

droggo avatar Feb 18 '16 09:02 droggo

Can be done. If we are going to do it, 3.2 would be the time. If we did it, I think the behavior should be setup to be turned off, or default to turned off and you have to turn it on. I think just changing it and making that the only way would be problematic for some folks.

jeffscottbrown avatar Feb 19 '16 00:02 jeffscottbrown

I think the project at https://github.com/jeffbrown/paramsandbody demonstrates the behavior in question. The README.md there describes how it currently behaves. That app is currently a 2.5.3 app that I created to address someone else's question about how this used to work.

jeffscottbrown avatar Feb 19 '16 10:02 jeffscottbrown

I think this could be accomplished by registering a custom data binding source creator. That isn't ideal, but isn't horrible either, and could be done without making any changes to core. We have no documentation on how to do that. One of the things that could come out of the exercise is those docs.

jeffscottbrown avatar Sep 07 '16 18:09 jeffscottbrown

+1 for this task

allnightlong avatar Dec 14 '17 16:12 allnightlong

+1 I would be interested in what would be involved, with creating a custom data binding source creator.

virtualdogbert avatar Feb 13 '18 17:02 virtualdogbert

+1 for at least to have a documentation

Current behaviour doesn't make much sense to me: depends on the request it either includes or not URL parameters. I think URL parameters should override once from the body if colliding as they were used to find the action. If collision was not intended developer may easily fix it on the server side (UrlMapping and Command object) by renaming placeholder name and need no changes on the client side. Another solution may be to bind URL parameters into the Map inside Command object. If the name of the Map cannot be the name in the body it will create a separate namespace to avoid collision.

C06A avatar Feb 13 '18 18:02 C06A

I will look into it. Thanks for the feedback.

jeffscottbrown avatar Feb 13 '18 18:02 jeffscottbrown