I am following the directions in the docs, here:
http://grails.org/doc/2.3.8/guide/webServices.html#hypermedia
Why won't grails produce HAL-formatted output, as shown in the documentation?
I have a domain object which I have mapped with the @Resource annotation:
@Resource(uri='/documentCatalogs', formats = ['json', 'xml'], readOnly = true)
class DocumentCatalog {
String entityType
String actionCode
...
}
...and in my conf/spring/resources.groovy, I have configured the HAL JSON renderer beans:
import com.cscinfo.platform.api.formslibrary.DocumentCatalog
import grails.rest.render.hal.HalJsonCollectionRenderer
import grails.rest.render.hal.HalJsonRenderer
// Place your Spring DSL code here
beans = {
halDocumentCatalogRenderer(HalJsonRenderer, DocumentCatalog)
halDocumentCatalogCollectionRenderer(HalJsonCollectionRenderer, DocumentCatalog)
}
Using the debugger, I confirmed that the initialize() method on HalJsonRenderer is called and that it is constructed with the correct targetType.
I send a rest call using Postman:
http://localhost:8080/formslibrary/documentCatalogs/3
Accept application/hal+json
And I get back a response which is regular JSON and doesn't contain any links:
{
"class": "com.cscinfo.platform.api.formslibrary.DocumentCatalog",
"id": 3,
"actionCode": "WITH",
"entityType": "LLP",
...
}
What did I miss? Is there some plugin or configuration setting I have to enable for this behavior? Is there some additional mapping property somewhere that's not documented?
Figured it out! There are multiple aspects of the fix...
I had to add "hal" as one of the listed formats in the @Resource annotation:
@Resource(uri='/documentCatalogs', formats = ['json', 'xml', 'hal'])
Some hunting around in the debugger revealed that Grails will blithely ignore the Accept
header, based on the UserAgent string that is sent from the client. (In my case, since I'm using Postman, it was the Google Chrome UA string.)
One workaround for the Accept
header issue is to add ".hal" to the end of the URL:
http://localhost:8080/formslibrary/documentCatalogs/3.hal
This isn't a very good solution IMO, since the HAL URLs generated by the renderer don't end in ".hal" by default.
A better solution is to fix Grails' handling of the accept header by updating the config. In Config.groovy, you will see a line that says:
grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident']
Change it to:
grails.mime.disable.accept.header.userAgents = ['None']
This forces Grails to honor the Accept
header, regardless of the user agent.
Hope this helps somebody else who's hitting the same issue.
P.S. It's really helpful to put a breakpoint in the ResponseMimeTypesApi#getMimeTypesFormatAware(...)
method.