CFC, returnForm, JSON, and content-type

This post is more than 2 years old.

I could have sworn that in ColdFusion 9, when asking a CFC to return JSON data with returnFormat=json, that ColdFusion used a response type of application/json. However, it looks like this is not the case. Maybe this behavior changed or maybe I just assumed wrong, but I'm definitely seeing an incorrect content type. Here is a quick example and a possible fix.

First, a simple CFC with two remote methods:

component {

remote function getone() {

	return 1;
}

remote function gettwo() {

	return 2;
}

}

And then a quick front end client for it:

<cfajaxproxy cfc="test" jsclassname="theproxy"> <script>

var foo = new theproxy(); var result = foo.getone(); alert(result); var result = foo.gettwo(); alert(result); </script>

When I check the response types in Chrome, I see...

So, in my particular case, I had a core CFC that my remote CFCs extended. I was able to add this to the constructor area and it worked fine:

<cfcontent type="application/json">

It just so happened that my base CFC was tag based so that worked ok. So what about script? This code works fine:

response = getPageContext().getResponse(); response.setContentType("application/json");

But oddly, when placed in the constructor area of my CFC above, it made everything use that content type, ie both the CFM and the CFC. That seemed odd. I'm assuming cfajaxproxy actually ran the CFC when creating the proxy. This seems to be an issue with cfajaxproxy only though. I changed my front end to a simple jQuery version and it worked fine. Here is my front end now and the CFC after.

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $(document).ready(function() { $.get("test.cfc?method=getone&returnformat=json",{}, function(res) { alert(res); },"json"); }) </script>

component {

response = getPageContext().getResponse();
response.setContentType("application/json");

remote function getone() {

	return 1;
}

remote function gettwo() {

	return 2;
}

}

One last tip. This is something I learned from Mark Drew a long time ago. Don't forget that CFCs can also use the constructor area to preselect a method returnformat. So in the CFC above, I can also do:

url.returnformat="json";

What's nice then is that people calling my CFC don't have to bother specifying it.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Glen Dunlop posted on 4/2/2011 at 9:04 PM

Ray, I think this might be a Chrome issue rather than a CF issue. If I do this in FireFox with fireBug it is displayed as Json.

Comment 2 by Raymond Camden posted on 4/2/2011 at 9:08 PM

I'm not seeing that in Firefox 4. The response type was still test/html.

Comment 3 by Glen Dunlop posted on 4/2/2011 at 9:45 PM

Did not know FF4 had been finally released :(

Anyway even after downloading that I still see JSon, I also don't see the text/html like you are either. Can you explain what section of fireBug that is, cause I don't see that. Maybe it is a platform difference.

Comment 4 by Raymond Camden posted on 4/2/2011 at 9:47 PM

I was in the Net panel, on the URL that was for the CFC, and I clicked the Headers panel. In response headers I saw the wrong type. When I added my fix, it was right. This was with the final jQuery version, NOT Ajax proxy. (Just to make sure we are on the same boat.)

Also - JSON crap changed quite a bit in the 9 timeframe. I'm on 901+CHF. You?

Comment 5 by Glen Dunlop posted on 4/2/2011 at 9:52 PM

I use ExtJS Core, and I am using chf9010001.

Comment 6 by Raymond Camden posted on 4/2/2011 at 9:54 PM

Just to make things simpler - can you try my jQuery one? It uses the CDN, so you should be able to run as is.

Comment 7 by Roberto posted on 4/2/2011 at 10:07 PM

Ray, is possibile to use json returned by serializeJson function with jQuery tmpl? ...
http://stackoverflow.com/qu...
I had to use cfjson...

thanks!

Comment 8 by Glen Dunlop posted on 4/2/2011 at 10:10 PM

Was not able to see what you see, I modified the code a little to reflect it correctly.

index.cfm

<html>
<body>

<cfajaxproxy cfc="test" jsclassname="theproxy">
<script>

var foo = new theproxy();
var result = foo.getone();
console.log(result);
var result = foo.gettwo();
console.log(result);
</script>

</body>
</html>

test.cfc

component {

remote function getone() {

return '{"errors":[{"ValidationError": {"validationLevel":"property","message":"Please enter your name","class":"system.domains.modules.blog.blogComment","property":"name","validationType":"NOTEMPTY"}},{"ValidationError": {"validationLevel":"property","message":"Please enter a valid email address","class":"system.domains.modules.blog.blogComment","property":"email","validationType":"NOTEMPTY"}},{"ValidationError": {"validationLevel":"property","message":"Please enter your comment","class":"system.domains.modules.blog.blogComment","property":"comment","validationType":"NOTEMPTY"}}],"status":"failed"}';
}

remote function gettwo() {

return 2;
}

}

Method one returns Json as it supposed too, because that is what it is.
Method two returns text as that is what it is.

Comment 9 by Raymond Camden posted on 4/2/2011 at 10:18 PM

@Glen: Respectfully I think you are wrong about your change to method 1. Why would you return the JSON yourself when CF can take a struct and convert it to JSON for you automatically? The whole point of this blog post is "Should CF uses the right content type when we request JSON using returnFormat." That's an automatic feature of CF. You are doing the JSON manually (which I think is a mistake, will describe below why) which is a different manner.

Now - my problem with you doing the JSON manually is that CF is going to see that as a string. When it adds returnFormat=json, it's going to JSON-ify the JSON itself. (It should - will confirm.) Your method as is would only be valid if you used returnformat=plain. That tells CF to not muck with the response at all.

As to your second method, I don't think you are getting the point of this. The point is - returnFormat=json tells CF to JSONify the response. '2' comes back as just 2 in JSON anyway I believe. But pretend I had used something like [] instead. In other words, let's not focus on my simple results - that really isn't relevant.

@Roberto: Um maybe - can we take this offline since it's a different topic?

Comment 10 by Glen Dunlop posted on 4/2/2011 at 10:19 PM

Ok Tried it with ExtJS Core, CFAjaxProxy and your jQuery example.

Every example if it is not a Json being returned will be returned as HTML, if it is a valid Json string then there is a Json tab when you drop the request to show the responce and post information.

Still don't see what the problem is.

Comment 11 by Raymond Camden posted on 4/2/2011 at 10:22 PM

Correction: So CF sees a string and leaves it alone. So Glen, your JSON string result isn't re-JSON-ified, but again, it goes against the whole point here. The point is the CF provides a way to take your CFC methods and have them be auto-converted to JSON.

And btw - using your return, the content type was still incorrect.

Comment 12 by Raymond Camden posted on 4/2/2011 at 10:23 PM

Look in the headers. To be clear, this is NOT something that causes a bug. My code w/o the response header changes works fine. I was trying to get the content type... "more proper" I guess.

Comment 13 by Glen Dunlop posted on 4/2/2011 at 10:24 PM

Ray, how can it return it as Json?

Json is built using valid keyword/value pairs, how can it return what the number 1/2 as Json without having the required information to be a Json?

ColdFusion might be doing an isJson to change the returntype in this example you put forward, it is the only explanation.

Comment 14 by Glen Dunlop posted on 4/2/2011 at 10:26 PM

Sorry Ray the point is if you return a valid Json string as I outlined in my example. I clearly see Json in fireBug and can drill into the nodes of the structure, if I do what you do, I do see just HTML but I think that is expected as I explained.

Comment 15 by Raymond Camden posted on 4/2/2011 at 10:30 PM

Again - I am not talking about the JSON string. It is returned correctly. I am talking about the content type of the result. Nothing more. Does that distinction make sense? Did you read about how I added <cfcontent>? I didn't tweak the actual data. Only the content type of the response.

As to your comment 13 - CF supports turning stuff into JSON. Has since version 8. But that's not the point of this blog entry in any way.

Comment 16 by Glen Dunlop posted on 4/2/2011 at 10:31 PM

Here is something you might think stranger, in jQuery if I use your exact code it does not return Json in the fireBug console.

Yet if I change your example to

<script type="text/javascript" src="http://ajax.googleapis.com/..."></script>
<script>
$(document).ready(function() {
$.get("test.cfc?method=getone&returnformat=json",{}, function(res) {
console.log(res);
},"json");
})
</script>

I see the Json tab, will send you an image off list to show you.

Comment 17 by Glen Dunlop posted on 4/2/2011 at 10:39 PM

Ray, I seriously get your point. But I am not seeing what you see, unless there is an alert() there. Even then I do not see in the Net tab the text/html I just see status 200.

I am also very aware of how ColdFusion converts to Json, I have been doing Ajax development in CF for 7-8 years now and never had an issue.

but if you are using alerts instead of console.log, then like I said it looks like this is an actual browser issue with firebug and not a ColdFusion problem.

Comment 18 by Raymond Camden posted on 4/2/2011 at 10:41 PM

Got a lot of moving parts here. ;) Can you please focus though on the _Headers_. I'm not terribly concerned with the resulting data as it works for me (if not for you we can open a new thread). Again - let's focus on the core issue here - which is not necessarily a bug folks need to care about, but is more about what SHOULD happen, and that is this core principle:

If I tell CF to "auto jsonify" a result, it should also auto change the content type of the result (along with JSON-ifing) the data.

That's all I'm saying here.

Comment 19 by Raymond Camden posted on 4/2/2011 at 10:43 PM

I'm not worried about the status code. I'm worried about the content type.

Comment 20 by Glen Dunlop posted on 4/2/2011 at 10:54 PM

But Ray, it is changing the content type. And that is what I see is happening, provided it is a valid Json being returned.

Comment 21 by Raymond Camden posted on 4/2/2011 at 10:58 PM

So to be clear, when you expand the result in Firebug and look at the header you see application/json? Look at my very first screen shot (my only shot), the 4th column says text/html. That is what I'm saying is incorrect.

Comment 22 by Glen Dunlop posted on 4/2/2011 at 11:15 PM

The point I was trying to make is that a string like 1 can't be converted to a Json struct, and object sure can, a struct sure can etc. A string is different, it doesn't have any more information to return it as a key/value pair.

Hope the clarifies what I was actually saying, and not disputing the conversion process by returning a json string like I did.

To illustrate

<cfset myStruct = {} />
<cfset myStruct.test = 'one' />
<cfreturn myStruct />

Returns as a Json object

<cfset mySting = 'Glen Dunlop' />
<cfreturn myString />

Returns as a string, so no conversion takes place.

Comment 23 by Raymond Camden posted on 4/2/2011 at 11:23 PM

@Glen: Agreed, yep.

Comment 24 by Ben Nadel posted on 4/5/2011 at 6:41 PM

Awesome tip on using URL to predefine the returnFormat:

url.returnformat="json";

Groovy!

Comment 25 by Raymond Camden posted on 4/5/2011 at 6:44 PM

That was Mark Drew's discovery. It works really well I think. Anything to minimize the amount of code your callers have to use is a good thing I think.

Comment 26 by Ben Nadel posted on 4/5/2011 at 6:48 PM

@Ray, absolutely! Plus, less for you type type in your CFFunction tags!

Comment 27 by Raymond Camden posted on 4/5/2011 at 6:51 PM

Oh snap - now you sound something I can pounce on! ;)

I would propose that - normally (nothing is 100%) you should refrain from ever using returnFormat in your cffunction tags themselves. The method should be as ignorant as possible about the callers intended use of the data.

Being preachy there - so take with large grain of salt.

Comment 28 by Ben Nadel posted on 4/5/2011 at 6:57 PM

Ha ha ha, I won't argue with that :)

Comment 29 by Phillip Senn posted on 4/5/2011 at 11:51 PM

I wonder if you could use

<cfparam name="url.returnformat" default="json">
in the constructor instead of cfset.

I'm still on version 8 btw.

Comment 30 by Raymond Camden posted on 4/5/2011 at 11:56 PM

I bet it works. But- hey - don't wonder - try it and tell us. :)

Comment 31 by Phillip Senn posted on 4/10/2011 at 5:36 AM

I just thought about this post while reading Rebecca Murphey's jQuery Fundamentals at http://jqfundamentals.com/b....
"for JSON data, the Content-type header should be application/json".
I'll be sure to put <cfcontent type="application/json"> in the constructor of all my remote cfcs.

Comment 32 by Stefan Richter posted on 11/15/2011 at 2:46 PM

Old thread I know, but what is the conclusion? Is this a bug in CF, or are we encouraged to set the content type manually?

I just tried this with CF 9 under OSX and I too see text/html; charset=UTF-8 as the content type when returning a JSON response via returnformat=json

Comment 33 by Raymond Camden posted on 11/15/2011 at 4:48 PM

I'd say it is still an issue - just one that doesn't seem to impact me much. I use the json argument in my jQuery calls and it just plain works.

Comment 34 by Jeff Regan posted on 11/25/2011 at 8:11 AM

I have an application that uses jQuery and AJAX to get employee records. The issue is that employee numbers are indeed numbers and some of them have leading zeroes. I am using json.cfc to produce the JSON because it allows me to format numbers as strings and preserve the leading zeroes.

Is there anything in CF that will allow me to use their native JSON functionality to achieve the same result?

I also set the status code, content length and message using setStatus and setContentLength for success and sendError for errors.

Comment 35 by Raymond Camden posted on 11/27/2011 at 12:32 AM

You want to ensure you are on the -very- latest CF, (901+CHF). We made multiple changes to JSON serialization over time. I think, however, we may still convert "000N" to "N", but it is worth checking.

You can - if you want - add the values. For example, with SQL you can select a column and prefix it with something.

Comment 36 by Stefan Richter posted on 2/1/2012 at 2:42 AM

Just to chime in, this bugs me greatly (wrong content type being sent by CF for JSON data).
Particularly during debugging (Chrome console for example) it is annoying that CF sends text/html as the content type.

I'll try setting the content-type header manually. Annoyingly.