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 2008 (Washington, D.C.) with:

Parsing AngularJS Request Data On The Server Using ColdFusion

By Ben Nadel on

By default, AngularJS posts all data to the server in JSON (JavaScript Object Notation) format. Unlike a regular "Form post," however, ColdFusion won't automatically parse the incoming request and add it to the Form scope. This means it's up to you to manually parse the data. Fortunately, it only takes a few lines of ColdFusion code.

To see this in action, I created a tiny AngularJS demo that posts data to the server using a subset of the HTTP methods: GET, POST, PUT, and DELETE. AngularJS will accept just about any "data" that you give it; however, I try to always pass an object. Even if that object has only one key, I find the consistency of a top-level object makes life a lot easier in the long run.

  • <!doctype html>
  • <html ng-app="Demo">
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • Parsing AngularJS Request Data On The Server Using ColdFusion
  • </title>
  • </head>
  • <body ng-controller="DemoController">
  •  
  • <h1>
  • Parsing AngularJS Request Data On The Server Using ColdFusion
  • </h1>
  •  
  • <!-- For each type of HTTP method, output the echoed result. -->
  • <div ng-repeat="dump in cfdumps">
  •  
  • <h3>
  • {{ dump.method }}
  • </h3>
  •  
  • <div ng-bind-html="dump.html">
  • <!-- To be populated with the CFDump from the server. -->
  • </div>
  •  
  • </div>
  •  
  •  
  • <!-- Initialize scripts. -->
  • <script type="text/javascript" src="../jquery/jquery-2.1.0.min.js"></script>
  • <script type="text/javascript" src="../angularjs/angular-1.2.4.min.js"></script>
  • <script type="text/javascript">
  •  
  • // Define the module for our AngularJS application.
  • var app = angular.module( "Demo", [] );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // I control the main demo.
  • app.controller(
  • "DemoController",
  • function( $scope, $http ) {
  •  
  • // I hold the data-dumps of the FORM scope from the server-side.
  • $scope.cfdumps = [];
  •  
  • // Make an HTTP request for each type of verb.
  • angular.forEach( [ "get", "post", "put", "delete" ], makeRequest );
  •  
  •  
  • // ---
  • // PRIVATE METHODS.
  • // ---
  •  
  •  
  • // I post data to the API using the given method type.
  • function makeRequest( method ) {
  •  
  • // AngularJS will try to work with ANY type of data that you pass
  • // in the "data" property. However, I try to ALWAYS pass an object
  • // with key-value pairs as I find that this makes the data easier
  • // to consume on the server.
  • var request = $http({
  • method: method,
  • url: "echo.cfm",
  • data: {
  • id: 4,
  • name: "Kim",
  • status: "Best Friend"
  • }
  • });
  •  
  • // Store the data-dump of the FORM scope.
  • request.success(
  • function( html ) {
  •  
  • $scope.cfdumps.push({
  • method: method.toUpperCase(),
  • html: html
  • });
  •  
  • }
  • );
  •  
  • }
  •  
  • }
  • );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // I override the "expected" $sanitize service to simply allow the HTML to be
  • // output for the current demo.
  • // --
  • // NOTE: Do not use this version in production!! This is for development only.
  • app.value(
  • "$sanitize",
  • function( html ) {
  •  
  • return( html );
  •  
  • }
  • );
  •  
  • </script>
  •  
  • </body>
  • </html>

This code posts to the server; then, the server parses the request data, adds it to the Form scope, and echoes the Form scope back to the client in the response (using CFDump).

  • <cfscript>
  •  
  • // Since we need to deserialize and consume the incoming request, there are a number
  • // of things that can go wrong.
  • try {
  •  
  • requestBody = toString( getHttpRequestData().content );
  •  
  • // Not every type of request will have a "body" (ex, "GET"). But, for this demo,
  • // we're going to assume the body, if it exists, will always be an object. I find
  • // an object easier to work with - I never let the client pass in a simple value
  • // or an array.
  • if ( len( requestBody ) ) {
  •  
  • structAppend( form, deserializeJson( requestBody ) );
  •  
  • }
  •  
  • } catch ( any error ) {
  •  
  • // The incoming request data was either not JSON or was not an "object". A this
  • // point, you might want to throw a custom error; or, you might want to let the
  • // request continue and defer processing logic to some controller.
  • // --
  • // throw( type = "BadRequest" );
  •  
  • }
  •  
  • // Echo the state of the Form scope (output on the client).
  • writeDump( var = form, label = "Form Scope" );
  •  
  • </cfscript>

As you can see, there's very little logic here. The incoming request body can be accessed using the getHttpRequestData() function. I chose to append the data to the existing Form scope; but, there's no rule that says you have to do that.

When we run the above code, we get the following output:


 
 
 

 
 Parsing AngularJS request data on the server using ColdFusion and the form scope. 
 
 
 

Again, you don't have to pass in an object. But, I find it creates a cleaner, more consistent solution; especially if you want to append the incoming data to the Form scope or some other type of "request collection," that many frameworks use.




Reader Comments

I think Angular sets the "Content-Type" request header to "application/json". To make your code more full proof, you could just add something to your onRequest event handler to look if the "Content-Type" header is "application/json" and if it is, then do your deserialization.

This would avoid potential issues w/normal form posts and you could add the base code into any site, so that JSON data as the content body always gets translated into the FORM scope.

Reply to this Comment

@Dan,

Ah, very good idea! I just took a look at the source code and your are right - it looks like they use, "application/json;charset=utf-8".

And for others' reference, this can be accessed via:

getHttpRequestData().headers[ "content-type" ]

... of course, this header won't always exist, depending on the type of request. It looks like it only exists IF there is actual request content. As such, GET requests don't have a content-type.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.