The Ajax Proxy - adampresley/cf-basis GitHub Wiki

The AJAX Proxy

You can't throw a rock, let alone write a web application today without running into the word AJAX. Adobe ColdFusion and the Open Source engines OpenBD and Railo all offer some level of "web 2.0". Between remote CFC invocation or commands like CFAJAXPROXY there is already some support for building AJAX applications in CFML.

For me the breakdown in those methods start to occur when you find yourself needing more control. Regardless if that control is over the JavaScript code or how the CFML side handles your request, Basis offers a deceptively simple means of AJAX applications through the AJAX Proxy.

Setting Up

If you've started your Basis application by using the provided skeleton you will already find an ajaxProxy.cfc file in the root of your application folder. If you did not you will need to create such a file, and the one provided can make an easy start.

The first thing to note is that it extends Basis.AjaxProxy. This gives the AJAX Proxy component everything it needs to process your AJAX requests. You will also see two methods in this component. One named validateAccess() with a dummy condition that will never fire. This is where you can place any custom access validation, such as ensuring a user is logged in, or a session token is provided, etc. The other method is onAjaxError() which has a commented out example. You can use this method to do additional processing, such as writing to log, sending an email, etc whenever an error occurs during any of your AJAX requests.

The below example shows both methods in action. In validateAccess() the session scope is checked for an object called user, and throws an exception (which will be caught by the proxy) stating that the user needs to be authenticated. You may then check your response in your JavaScript to perhaps display a message to your user, or redirect to a log in page.

The onAjaxError() method catches exceptions while processing AJAX requests (such as the authentication error talked about above). In this example we are writing to the OpenBD log, setting the HTTP's response code to 500, and returning the error back to the calling JavaScript.

<cfcomponent extends="Basis.AjaxProxy" output="false">

	<cffunction name="validateAccess" access="private" output="false">
		<cfif !structKeyExists(session, "user")>
			<cfthrow type="custom" message="Not authenticated" detail="You are not authenticated. Please log in." />	
		</cfif>
	</cffunction>	

	<cffunction name="onAjaxError" access="private" output="false">
		<cfargument name="errorInfo" />

		<cfset writeLog(
			text = "ACTION = #request.rc.action# : #arguments.errorInfo.message#",
			type = "Error",
			log = "application"
		) />

		<cfheader statusCode="500" statusText="Internal Server Error" />
		<cfreturn {
			"message" = "An error occurred: #arguments.errorInfo.message#",
			"success" = false
		} />
	</cffunction>

</cfcomponent>

Once you have the proxy in place you will need a home for all of your AJAX handlers. An AJAX handler is a CFC component that executes a specific action. All AJAX handlers live in a subdirectory of root named ajax.

Your First AJAX Handler

So for your first foray into the AJAX Proxy in Basis let's start by creating a handler. Before we do create a new directory under the ajax directory named test. Once you have this new directory create a new file and name it helloWorld.cfc. This will be our AJAX handler.

But handler for what, you might ask? Well, because we have a component named helloWorld.cfc, and it resides in a directory named test, our action will be test.helloWorld. This is how the AJAX Proxy works. When an action variable is passed on the URL (or FORM) scope, much like regular Basis actions, they are routed to a particular component for handling.

Go ahead and open up your new component to edit it and make it look like this:

<cfcomponent extends="Basis.Service" output="false">
   
   <cffunction name="process" output="false">
      <!---
         Return some type of struct.
      --->
      <cfreturn { message = "Hello World!" } />
   </cffunction>

</cfcomponent>

Now comes the part where you get to see it in action. Assuming your site is at localhost, you can see this by browsing to http://localhost/ajaxProxy.cfc?method=process&action=test.helloWorld. You should see a response that looks like this:

{ MESSAGE: "Hello World!" }

Anatomy of an AJAX Handler

The above example demonstrates the most basic AJAX handler in the Basis framework. The directory name under ajax will be the name of the section of the action, and the CFC file name will be the same as the method portion of the action.

Your CFC AJAX handler will then extend the Basis.Service component, allowing the AJAX proxy to instantiate it and pass information to it as well. As a result all URL and FORM variables will be available to your CFC through the rc variable, just like in regular Basis controller components and views.

From there you create a single method named process() and this is where you will do all the work. Here you can query a database, call a web service, or ask other components for data. Then you return either an array or a structure and the AJAX proxy will automatically serialize your data to JSON, or JavaScript Object Notation.

Most everything you have access to in regular Basis controllers you have access to in your AJAX handler. The rc variable, the main factory, etc... Let's take a look at a more sophisticated example.

<cfcomponent extends="Basis.Service" output="false">
   
   <cffunction name="process" output="false">
      <cfset var service = application.theFactory.getService("Contact") />
      <cfset var data = {} />

      <!---
         Make sure we have a contact ID
      --->
      <cfif !structKeyExists(rc, "contactId") || val(rc.contactId) <= 0>
         <cfthrow message="Please provide a valid contact ID" />
      </cfif>

      <cfset data = service.getContact(contactId = rc.contactId) />
      <cfreturn data />
   </cffunction>

</cfcomponent>

Notice that we are using application.theFactory to get our service components, just like anywhere else in Basis. Also notice that if a valid contact ID isn't passed in we are throwing an exception. The AJAX Proxy will catch this exception and place it into a structure with two keys: success and message, where success will be false and message will contain the message from your call to . This is then serialized to JSON and sent out to the caller.

Easy right? :)

Next up: Writing Plugins For Basis

⚠️ **GitHub.com Fallback** ⚠️