Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Ray Camden

Returning NULL Values In JSON Using SerializeJSON() And ColdFusion

By Ben Nadel on
Tags: ColdFusion

As I've been setting up a JSON-RPC (Remote Procedure Call) API for a ColdFusion project, I've been learning a few little tips and trips about JSON formation. Last week, I talked about how struct keys defined using array-notation maintain case during serialization. This week, in accordance with the JSON-RPC spec, I learned that you can return NULL JSON values by storing NULL ColdFusion values.

To demonstrate, I've mocked up an incomplete JSON-RPC example. According to the JSON-RPC specifications, a properly formed response cannot contain both an Error and a Result value at the same time; one of them must always be null. In order to ensure that a true JSON-null is returned, you have to store a null value in your ColdFusion response struct.

  • <!---
  • Define our basic JSON-RPC response structure. Note that we
  • are using array-notation in order to maintain case in the
  • serialization process.
  • --->
  • <cfset response = {} />
  • <cfset response[ "jsonrpc" ] = 2.0 />
  • <cfset response[ "result" ] = "Blam!" />
  • <cfset response[ "error" ] = {} />
  •  
  •  
  • <!---
  • For JSON-RPC, we cannot return both a RESULT and an ERROR in
  • same response. One of them has to be null. In order to return a
  • null value in the a JSON-serialization, we need to actually store
  • a NULL value in the ColdFusion struct.
  • --->
  • <cfset response.error = javaCast( "null", "" ) />
  •  
  •  
  • <!--- Serialize the JSON-RPC response. --->
  • <cfset serializedResponse = serializeJSON( response ) />
  •  
  • <!---
  • Stream the JSON response back to the client.
  •  
  • NOTE: The Mime-Type that we are using here is plain text only for
  • debugging purposes. In a real-world situation, you'd be returning
  • the JSON as application/json.
  • --->
  • <cfcontent
  • type="text/plain"
  • variable="#toBinary( toBase64( serializedResponse ) )#"
  • />

As you can see above, we are using javaCast() to store our null ColdFusion value. Doing so essentially destroys the usability of the key from a ColdFusion standpoint; but, from a JSON serialization standpoint, it's just what the doctor ordered. Running the above code gives us the following JSON response:

{ "jsonrpc":2.0, "error":null, "result":"Blam!" }

As you can see, the "error" key contains a true null value.

While this isn't the point of the post in any way, I should also mentioned that if you use ColdFusion to deserialize a JSON string that contains a null value, ColdFusion converts it into the string, "null". As such, if you're setting up a JSON-RPC API, you'll probably end up having to use a combination of structKeyExists() and (neq "null") statements.

Going from a typeless, case-insensitive language like ColdFusion to a format like JSON can prove to be a bit tricky at times; but, other than a few irksome numeric-conversions, ColdFusion tends to handle it surprisingly well - as long as you know how to work the system.




Reader Comments

I have a strong emotional response to JSON-RPC. We internally have a server API that requires requests made in JSON and returns JSON responses. Getting back JSON responses is quite normal, and many interfaces implement this without calling themselves 'JSON-RPC'.

The significant issue is making requests in JSON. You must serialize the request with JSON.stringify (not avaiable in <IE8) and is not backwards compatible with HTML forms. If you are using jQuery, it will try to URLEncode your JSON object and seems to like to do the same to stringified JSON, so I also have to set processData false. I've ended up making a whole API to handle all of this in order to make even basic requests to the server.

So I beg you, change the name!

@Drew,

For this project we're actually integrating with a 3rd party system that will be posting to our API. I am not even sure if JSON-RPC is easily doable with an AJAX-style approach. You can probably manually finagle the way data is sent; but in our case, the JSON value actually has to be posted as the request body (ie. getHTTPRequestData().content).

Honestly, I'm not crazy about the JSON-RPC specs; as you are saying, there's all kinds of complications when it comes to dealing with the browser. I'm only using it because it's pre-established in our integration spec.

At the end of the day, I'd rather just supply a standard URL interaction and then just have a normalized response structure. This spec seems to complicate my code somewhat :)

@Ben,

It is further complicated in the case where you need to push things through a proxy. For instance, the curl module in PHP does not support JSON. I am currently using Apache mod proxy for testing, and still unsure what to use in production hopefully Ruby can provide a cross platform/http-server solution.

@Henry,

Nope, I was lucky to find it, otherwise jQuery tries to serialize your data for you. I had the unfortunate experience of debugging this while using a proxy, so after many hours of Wireshark I discovered the issue.

If you DeserializeJSON { "jsonrpc":2.0, "error":null, "result":"Blam!" }, you will not get back the original NULL value because ColdFusion9 cannot understand it.

On the other hand, if you ever use Railo 3.2, the result is even more interesting. When Railo encounter a null value, the struct key (in this case, "error") will be lost.

See my post regarding to DeserializeJSON() with the Railo team:

https://issues.jboss.org/browse/RAILO-1117

@Peter,

Hmm, looks like Railo is using the same "null query value" approach where null values become empty strings. Ultimately, I am not sure what the best solution is. Since we are talking between two systems, it definitely gets tricky!!

I've had good luck using Jackson for serializing/deserializing JSON with CF. It won't map to CFC instances, but it can handle nulls. It can work from cfmx-9, is very fast, and can be made to send integers as integers rather than floats.

Lots of great information and inspiration, which we all need! I really appreciate the efforts made by you for this. Well Done! Thanks for sharing the information with us.

@Mark,

Looks interesting (I just Googled "Jackson JSON" and I assume I found the right thing). Do you have problems with it converting strings to numbers? That's one of the biggest issues with CF-native JSON conversions that I see.

@Rupali,

Glad you find this helpful :)

@Ben
It depends on where the data you're serializing comes from. You might have to do a lot of javaCast()'s. You also have to watch out for CF converting all your struct keys to uppercase, unless you use array notation (since JSON is case sensitive). However, something like a cfquery (if comes from jdbc, not queryNew()) -- the data is already of the right type.

@Mark,

Thanks for the update. So far, the CF stuff hasn't been causing too much of an issue. But, we did just launch a beta API to the client application this afternoon. Soon, we'll see if "2" getting converted to 2.0 in the JSON will cause any type-mismatch errors (fingers crossed).