Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails 2 - produce JSON output automatically (like Spring 3.x does)

Tags:

json

grails

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?

like image 977
nickdos Avatar asked Aug 09 '12 03:08

nickdos


2 Answers

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
                }

        }

    }
}
like image 191
Fabiano Taioli Avatar answered Oct 18 '22 01:10

Fabiano Taioli


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
                }
            }
        }
    }
}
like image 3
nickdos Avatar answered Oct 18 '22 02:10

nickdos