Problem
Ofter we need to create RESTful API to READ data for existed domain objects with easy manipulation of fields in it. For example, we do not need to see in API result fields like ‘id’, ‘lastUpdated’, ‘createdBy’, collections, references and any other fields. Also we want to have easy way to change field name. For example, instead of ‘image’ you want ‘imageUrl’ because we need to put URL link there. And of course, we want to make different manipulations with fields, like put full URL or calculate whether shop is working now or anything else.
Solution
Of course, we can do it by simple code like
But when you have more then 20 fields in object and need to send complex structures, like send ‘address’ and ‘contact’ references but do not send ‘currentLocation’ and you have more then 10 of such objects – It became a nightmare! Support is even worst!
So, to solve this problem we create rather simple (at least when looking now on it) solution.
First define in UrlMapping something like:
So all READ API calls will be
‘/appName/api/users’ or ‘/appName/api/venues?format=json&max=10&offset=10′
In ‘ApiJsonRestController’ we need to get from domainInPlural real domain class name (through a simple mapping or complicated rule – up to you) and just send it to response:
In the result you will get list of domain instances with all fields – very Ugly.
Extend DomainClassMarshaller
Now is the most interesting part.
We need to override default Grails DomainClassMarshaller, so that during object rendering ours was used instead
It is a copy of DomainClassMarshaller with several modifications:
- We control whether to define id for object by protected needToDefineId()
- We control object id itself by protected getObjectIdentifier()
- processAdditionalFields() allow to put any fields you want which are not in domain
- We control fields to skip and alternative field name via protected methods getSkippedFields() and getAlternativeName(String originalName)
- We controll how to display references to other domains and collections via processSpecificFields()
So for each object where we have specific fields to skip and alternative name or some rules to display fields we need to create an extended class:
You can try to play with it, but once it is done you have no any problem with support. New fields added automatically, if you change field name it will be changed everywhere: in places where domain object rendered itself and in embedded object.
And do not forget to register your Marshallers!!! We do it in BootStrap.groovy:
1
Hi Michael,
Thanks for sharing, but wouldn’t something like this (http://www.jworks.nl/2011/08/15/excluding-fields-and-properties-from-marshalling-using-annotations-in-grails/) be easier? That way, you wouldn’t have to create a custom Marshaller per domain class, but you can just easily annotate your code.
Erik
Hi Erik,
Thanks for reply.
There are several points:
1) At some point of time this code can be re-written in annotations plus rest api way, but I’m not sure, as it is the matter of control on API.
2) We have complex rules per some domains with additional separate fields, different processing of existing fields – that’s why we use processSpecificFields, processSimpleField and processAdditionalFields methods. Agreed that this all can be done in Annotations and I’m thinking about this. But still have questions about control and changes – how much any change in annotations structure will cost.
3) You can easily Create Marshaller per several domains (I have this as well) just by modifying supports method