1
votes

The root symptom of our issue is that after switching our project from Grails 2.2.3 to 2.3.11, our jQuery Ajax calls started returning XML instead of JSON.

The code snippets below illustrate how things are configured in our GSP, controllers, and service and show an example of a static data set that is returned as an object (a list of maps containing string pairs of code/name values). The controller returns this list using the withFormat clause to the GSP. In Grails 2.2.3, this was always JSON, but now in 2.3.11, it is XML.

Through experimentation, I found that if I change the order of the JSON and XML lines in the withFormat clause in the controller to put JSON first, then everything works. I do not like the idea of changing every action in every controller to make this work again.

  • What changed in Grails 2.3.x to break this existing functionality?
  • What can we change with how we are making these calls to get the desired JSON functionality back instead of XML?
  • This seems like something that should be able to be configured at the application level and not change every jQuery Ajax call or change every controller action.

myTest.gsp

var fetchData = function () {
    $.ajax({
        url: "${g.createLink(controller:'myController', action:'myAction')}",
        async: true,
        type: 'get',
        dataType: "json",
        success: function (data) {
            if (data) {
                // Not shown -- Do something useful with the data
            }
        },
        error: function (request, status, error) {
            show.alert("Error with the data. \nStatus: " + status + ", \nError: " + error );
        }
    });
};

MyController.groovy

class MyController {
    def myService
    ...
    def myAction() {
        def results = myService.myAction()
        withFormat {
            xml { render results as XML }
            json { render results as JSON }
        }
    }
    ...        
}

MyService.groovy

class MyService {
    def myMap = [ AK: 'Alaska', AL:'Alabama', ... , WY:'Wyoming' ]
    def myAction() {
        def results = []
        myMap.each {
            def item = [:]
            item.code = it.key
            item.name = it.value
            result.add(item)
        }
        return results
    }
}    

Config.groovy

grails.mime.use.accept.header = true

UPDATE:

I have a "fix", but I'm not very happy with it and would welcome alternate answers or explanations as to why this functionality broke between 2.2.3 and 2.3.11.

I changed the order of the JSON and XML types in the withFormat closure in my controller action to put JSON first and the issue is "resolved".

I am not happy with this as it will require me to change all 68 of my actions in all of my controllers. This is introducing a lot of potential risk as other functionality may change with me changing this volume of code all for something that worked fine in a previous version of Grails. Is there something at a global level that I can change to address this?

MyController.groovy

class MyController {
    def myService
    ...
    def myAction() {
        def results = myService.myAction()
        withFormat {
            json { render results as JSON } // <-- MOVED THIS TO BE FIRST
            xml { render results as XML }
        }
    }
    ...        
}
1
Can you inspect Request and see what kind of response are you receiving, It looks you are receiving xml response instead of json response. Please confirm the same.JChap
Yes. We are getting back XML now and not JSON, but I'm not sure what changed between 2.2.3 and 2.3.11 to cause this or how to get it working again.GeoGriffin
Can you give us the Accept Header of Ajax Request ? Also try setting the Accept header to application/json. Check here stackoverflow.com/questions/1145588/…JChap

1 Answers

2
votes

Based on this article (http://mrhaki.blogspot.com/2014/07/grails-goodness-enable-accept-header.html) regarding accept headers, I added the following line to my Config.groovy and it corrected my issue.

Config.groovy

grails.mime.use.accept.header = true
grails.mime.disable.accept.header.userAgents = [] // <-- Added this line