In Spring MVC 3.x I can configure a ContentNegotiatingViewResolver
bean to automatically render any given endpoint in either JSON or XML simply by changing the file extension to .json
or .xml
. I assumed there was an equivalent functionality in Grails but I can't find it.
Everything I've read says I have to catch the incoming mime-type (using withFormat
) and then specify the JSON output using render as JSON
(or equivalent) in every one of my controller methods (e.g. rendering JSON with Grails?). Before I dive in and start adding JSON-specific code to my controllers I thought I'd ask here...
So my question is: Can I configure Grails 2 to automatically produce JSON output by simply adding a `.json' file extension (or changing the accept header) for any given URL?
I think you can easly to it using a grails filter
This is a filter I have done ab OAuth API in a mine application, it do xml,json and yalm based on accept headers
class RenderFilters {
def grailsApplication
def filters = {
multiFormat(controller: '*EndPoint', action: '*', search: true) {
after = { Map model ->
def accepts = request.getHeaders('accept')*.toLowerCase()
def out = model.containsKey('out')?model.out:model
if(accepts.any{ it.contains('json') }){
render(text: out as JSON, contentType: 'application/json', encoding:"UTF-8")
}
else if(accepts.any{ it.contains('yaml') }){
render(text: Yaml.dump(out), contentType: 'application/x-yaml;', encoding:"UTF-8")
}
else if(accepts.any{ it.contains('html') }){
render(text: out as JSON, contentType: 'application/json', encoding:"UTF-8")
}
else if(accepts.any{ it.contains('xml') }){
render(text: out as XML, contentType: 'application/xml', encoding:"UTF-8")
}
else {
render(text: out as JSON, contentType: 'application/json', encoding:"UTF-8")
}
false
}
before = {
def contentType = request.getHeader('Content-Type')?.toLowerCase()
if(!contentType) return true
if(contentType == 'application/json'){
params.body = JSON.parse(request.reader)
}
if(contentType == 'application/xml'){
params.body = XML.parse(request.reader)
}
if(contentType == 'application/x-yaml'){
params.body = Yaml.load(request.reader)
}
params.body = new TypeConvertingMap((Map) params.body)
true
}
}
}
}
For anyone coming across this SO question, I thought I'd include my final Grails (version 2.x) filter code, as it did differ from that in Fabiano's answer (above).
The following filter allows plain HTML content to be handled as normal by Grails and uses the Grails content negotiation mechanism to set the response.format
by file extension or accept header (depending on the conf settings: grails.mime.use.accept.header
& grails.mime.file.extensions
). I also added support for a JSONP callback wrapper.
import grails.converters.JSON
import grails.converters.XML
class RenderFilters {
def filters = {
multiFormat(controller: '*', action: '*', find: true) {
after = { Map model ->
def out = model?.containsKey('out')?model.out:model
if (response.format == "json" && params.callback) {
render(text: params.callback + "(${out as JSON})" , contentType: 'application/javascript', encoding:"UTF-8")
false
} else if (response.format == "json") {
render(text: out as JSON, contentType: 'application/json', encoding:"UTF-8")
false
} else if (response.format == "xml") {
render(text: out as XML, contentType: 'application/xml', encoding:"UTF-8")
false
}
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With