DevLearningTools

MODULE 14 · LESSON 04

JSON Responses

Returning well-structured JSON from ColdFusion: serializeJSON's query-format options, a real cross-engine difference in struct key casing, and why a remote CFC method doesn't return JSON by default.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

The previous lesson consumed JSON from an external API. This one builds it, returning a well-structured JSON response from your own ColdFusion code, with serializeJSON, and a couple of real gotchas that trip up a lot of people the first time: struct key casing, and what a remote CFC method actually returns by default.

Learning Objectives

After completing this lesson, you'll be able to:

  • Serialize a struct, array, or query to JSON with serializeJSON.
  • Control how a query serializes: row, column, or array-of-structs.
  • Return JSON correctly from both a plain .cfm page and a remote CFC method.
  • Know the real, engine-specific difference in how struct key casing actually gets preserved (or doesn't).

How a JSON Response Actually Goes Out

Struct / Array / Query

serializeJSON()

JSON String

Sent With the Right Content-Type

A Basic Manual JSON Response

Tag Syntax
<cfset responseData = { "status" = "success", "code" = 200 }>
<cfset jsonString = serializeJSON(responseData)>

<cfcontent type="application/json" reset="true">
<cfoutput>#jsonString#</cfoutput>
CFScript
responseData = { "status": "success", "code": 200 };
jsonResponse = serializeJSON(responseData);

cfcontent(type = "application/json", reset = "true");
writeOutput(jsonResponse);
NOTE

reset="true" clears any output already buffered on the page before this point, without it, stray whitespace or earlier output can corrupt the JSON the client actually receives.

serializeJSON's Arguments

ArgumentMeaning
dataThe struct, array, or query to serialize (required)
queryFormatrow (default), column, or struct, controls how a query serializes
useSecureJSONPrefixPrepends a security prefix to the output (default false)
useCustomSerializerWhether to use a custom serializer if one is defined (default true)

A Real Example: The Three Query Serialization Formats

The default row format is genuinely awkward for a modern frontend, struct is what most JavaScript code actually wants.

queryFormatOutput Shape
row (default){"COLUMNS":["CITY","STATE"],"DATA":[["Newton","MA"],["San Jose","CA"]]}
column{"ROWCOUNT":2,"COLUMNS":["CITY","STATE"],"DATA":{"CITY":["Newton","San Jose"],"STATE":["MA","CA"]}}
struct[{"CITY":"Newton","STATE":"MA"},{"CITY":"San Jose","STATE":"CA"}]
CFScript
jsonOutput = serializeJSON(myQuery, "struct");

A Real Correction: Struct Key Casing Isn't Fixed by Just Quoting Keys

A common claim is that quoting a struct literal's keys, {"name": "John"} instead of {name: "John"}, preserves lowercase casing in the resulting JSON. That's genuinely true on Lucee, but not on Adobe ColdFusion.

EngineActual Behavior
Adobe ColdFusionStruct keys are internally represented as all-uppercase, and serialize as all-uppercase, regardless of how the literal quoted them. Fixing this requires this.serialization.preservecaseforstructkey = true in Application.cfc, or the equivalent Administrator setting under Server Settings > Settings.
LuceeQuoted keys in a struct literal preserve their case; unquoted (bare word) keys get uppercased.
Application.cfc (Adobe ColdFusion)
component {
    this.serialization.preservecaseforstructkey = true;
}

A Real Gotcha: Remote CFC Methods Don't Return JSON by Default

By default, a remote CFC function's return value serializes to WDDX, not JSON. Getting JSON out of it requires asking for it explicitly.

CFScript
remote struct function getProductData() returnformat="json" {
    return { status: "success", productId: 101 };
}
NOTE

returnformat="json" can be set on cffunction itself, passed as a ?returnformat=json parameter in the calling URL, or set via a CFC proxy's setReturnFormat function, the URL parameter is exactly what ColdFusion's own Ajax bind expressions and cfajaxproxy generate automatically.

Common Beginner Mistakes

Assuming quoted struct literal keys fix case on Adobe ColdFusion

That's Lucee's behavior specifically. On Adobe ColdFusion, keys are uppercased regardless of quoting, this.serialization.preservecaseforstructkey=true is the actual fix.

Assuming a remote CFC method returns JSON automatically

The default is WDDX, not JSON. returnformat="json" (on the function, in the URL, or via a proxy) is required to actually get JSON back.

Forgetting reset="true" on cfcontent for a manual JSON response

Any output already buffered before that point stays in the response, potentially corrupting the JSON with stray content ahead of it.

Serializing a query with the default row format for a modern JavaScript frontend

row's columns/data-arrays shape is awkward to consume directly. struct produces the array-of-objects shape most frontend code actually expects.

Best Practices

  • Use queryFormat="struct" when a query's JSON is going to a modern frontend.
  • Set this.serialization.preservecaseforstructkey=true on Adobe ColdFusion (or rely on Lucee's quoted-key behavior) when lowercase/camelCase JSON keys actually matter.
  • Set returnformat="json" explicitly on a remote method, rather than depending on the WDDX default.
  • Always reset="true" before manually writing a JSON response with cfcontent.

Interview Questions

Does quoting a struct literal's keys preserve their case in JSON on Adobe ColdFusion?

No, that's Lucee-specific behavior. Adobe ColdFusion uppercases struct keys during serialization regardless of quoting, this.serialization.preservecaseforstructkey=true is the real fix there.

What format does a remote CFC method return by default, if returnformat isn't specified?

WDDX, not JSON. returnformat="json" needs to be set explicitly, whether on the function, as a URL parameter, or via a proxy's setReturnFormat.

What's the difference between serializeJSON's row, column, and struct query formats?

row (the default) produces separate columns and data arrays. column groups values by column name. struct produces an array of individual row objects, the shape most modern frontend code actually wants.

Summary

In this lesson, you returned JSON manually from a .cfm page, controlled query serialization format with serializeJSON, covered the real cross-engine difference in struct key casing (quoted keys on Lucee vs. an explicit setting on Adobe ColdFusion), and the real WDDX-by-default gotcha on remote CFC methods.

What's Next?

The next lesson covers authentication basics: verifying who's calling your API before letting them use it.

MORE IN APIS & MODERN DEVELOPMENT