9 min read

What is Direct?

Part of the power of any client-side library is its ability to tap nearly any server-side technology. That said, with so many server-side options available there were many different implementations being written for accessing the data.

Direct is a means of marshalling those server-side connections, creating a ‘one-stop-shop’ for handling your basic Create, Read, Update, and Delete actions against that remote data. Through some basic configuration, we can now easily create entire server-side API’s that we may programmatically expose to our Ext JS applications. In the process, we end up with one set of consistent, predefined methods for managing that data access.

Building server-side stacks

There are several examples of server-side stacks already available for Ext JS, directly from their site’s Direct information. These are examples, showing you how you might use Direct with a particular server-side technology, but Ext provides us with a specification so that we might write our own. Current stack examples are available for:

  • PHP
  • .NET
  • Java
  • ColdFusion
  • Ruby
  • Perl

These are examples written directly by the Ext team, as guides, as to what we can do. Each of us writes applications differently, so it may be that our application requires a different way of handling things at the server level. The Direct specification, along with the examples, gives us the guideposts we need for writing our own stacks when necessary. We will deconstruct one such example here to help illustrate this point.

Each server-side stack is made up of three basic components:

  • Configuration— denoting which components/classes are available to Ext JS
  • API— client-side descriptors of our configuration
  • Router— a means to ‘route’ our requests to their proper API counterparts

To illustrate each of these pieces of the server-side stack we will deconstruct one of the example stacks provided by the Ext JS team. I have chosen the ColdFusion stack because:

  • It is a good example of using a metadata configuration
  • DirectCFM (the ColdFusion stack example) was written by Aaron Conran, who is the Senior Software Architect and Ext Services Team Leader for Ext, LLC

Each of the following sections will contain a “Stack Deconstruction” section to illustrate each of the concepts. These are to show you how these concepts might be written in a server-side language, but you are welcome to move on if you feel you have a good grasp of the material.

Configuration

Ultimately the configuration must define the classes/objects being accessed, the functions of those objects that can be called, and the length (number) of arguments that the method is expecting. Different servers will allow us to define our configuration in different ways. The method we choose will sometimes depend upon the capabilities or deficiencies of the platform we’re coding to. Some platforms provide the ability to introspect components/classes at runtime to build configurations, while others require a far more manual approach. You can also include an optional formHandler attribute to your method definitions, if the method can take form submissions directly. There are four basic ways to write a configuration.

Programmatic

A programmatic configuration may be achieved by creating a simple API object of key/value pairs in the native language. A key/value pair object is known by many different names, depending upon the platform to which we’re writing for: HashMap, Structure, Object, Dictionary, or an Associative Array. For example, in PHP you might write something like this:

$API = array(
‘Authors’=>array(
‘methods’=>array(
‘GetAll’=>array(
‘len’=>0
),
‘add’=>array(
‘len’=>1
),
‘update’=>array(
‘len’=>1
)
)
)
);


Look familiar? It should, in some way, as it’s very similar to a JavaScript object. The same basic structure is true for our next two methods of configuration as well.

JSON and XML

For this configuration, we can pass in a basic JSON configuration of our API:

{
Authors:{
methods:{
GetAll:{
len:0
},
add:{
len:1
},
update:{
len:1
}
}
}
}


Or we could return an XML configuration object:

<Authors>
<methods>
<method name=”GetAll” len=”0″ />
<method name=”add” len=”1″ />
<method name=”update” len=”1″ />
</methods>
</Authors>


All of these forms have given us the same basic outcome, by providing a basic definition of server-side classes/objects to be exposed for use with our Ext applications. But, each of these methods require us to build these configurations basically by hand. Some server-side options make it a little easier.

Metadata

There are a few server-side technologies that allow us to add additional metadata to classes and function definitions, using which we can then introspect objects at runtime to create our configurations. The following example demonstrates this by adding additional metadata to a ColdFusion component (CFC):

<cfcomponent name=”Authors” ExtDirect=”true”>
<cffunction name=”GetAll” ExtDirect=”true”>
<cfreturn true />
</cffunction>
<cffunction name=”add” ExtDirect=”true”>
<cfargument name=”author” />
<cfreturn true />
</cffunction>
<cffunction name=”update” ExtDirect=”true”>
<cfargument name=”author” />
<cfreturn true />
</cffunction>
</cfcomponent>


This is a very powerful method for creating our configuration, as it means adding a single name/value attribute (ExtDirect=”true”) to any object and function we want to make available to our Ext application. The ColdFusion server is able to introspect this metadata at runtime, passing the configuration object back to our Ext application for use.

Stack deconstruction—configuration

The example ColdFusion Component provided with the DirectCFM stack is pretty basic, so we’ll write one slightly more detailed to illustrate the configuration. ColdFusion has a facility for attaching additional metadata to classes and methods, so we’ll use the fourth configuration method for this example, Metadata.

We’ll start off with creating the Authors.cfc class:

<cfcomponent name=”Authors” ExtDirect=”true”>
</cfcomponent>


Next we’ll create our GetAll method for returning all the authors in the database:

<cffunction name=”GetAll” ExtDirect=”true”>
<cfset var q = “” />
<cfquery name=”q” datasource=”cfbookclub”>
SELECT AuthorID,
FirstName,
LastName
FROM Authors
ORDER BY LastName
</cfquery>
<cfreturn q />
</cffunction>


We’re leaving out basic error handling and stuff, but these are the basics behind it. The classes and methods we want to make available will all contain the additional metadata.

Building your API

So now that we’ve explored how to create a configuration at the server, we need to take the next step by passing that configuration to our Ext application. We do this by writing a server-side template that will output our JavaScript configuration. Yes, we’ll actually dynamically produce a JavaScript include, calling the server-side template directly from within our <script> tag:

<script src=”Api.cfm”></script>


How we write our server-side file really depends on the platform, but ultimately we just want it to return a block of JavaScript (just like calling a .js file) containing our API configuration description. The configuration will appear as part of the actions attribute, but we must also pass the url of our Router, the type of connection, and our namespace. That API return might look something like this:

Ext.ns(“com.cc”);
com.cc.APIDesc = {
“url”: “/remote/Router.cfm”,
“type”: “remoting”
“namespace”: “com.cc”,
“actions”: {
“Authors”: [{
“name”: “GetAll”,
“len”: 0
},{
“name”: “add”,
“len”: 1
},{
“name”: “update”,
“len”: 1
}]
}
};


This now exposes our server-side configuration to our Ext application.

Stack deconstruction—API

The purpose here is to create a JavaScript document, dynamically, of your configuration. Earlier we defined configuration via metadata. The DirectCFM API now has to convert that metadata into JavaScript. The first step is including the Api.cfm in a <script> tag on the page, but we need to know what’s going on “under the hood.”

Api.cfm:
<!— Configure API Namespace and Description variable names —>
<cfset args = StructNew() />
<cfset args[‘ns’] = “com.cc” />
<cfset args[‘desc’] = “APIDesc” />
<cfinvoke component=”Direct” method=”getAPIScript”
argumentcollection=”#args#” returnVariable=”apiScript” />
<cfcontent reset=”true” />
<cfoutput>#apiScript#</cfoutput>


Here we set a few variables, that will then be used in a method call. The getAPIScript method, of the Direct.cfc class, will construct our API from metadata.

Direct.cfc getAPIScript() method:

<cffunction name=”getAPIScript”>
<cfargument name=”ns” />
<cfargument name=”desc” />
<cfset var totalCFCs = ” />
<cfset var cfcName = ” />
<cfset var CFCApi = ” />
<cfset var fnLen = ” />
<cfset var Fn = ” />
<cfset var currFn = ” />
<cfset var newCfComponentMeta = ” />
<cfset var script = ” />
<cfset var jsonPacket = StructNew() />
<cfset jsonPacket[‘url’] = variables.routerUrl />
<cfset jsonPacket[‘type’] = variables.remotingType />
<cfset jsonPacket[‘namespace’] = ARGUMENTS.ns />
<cfset jsonPacket[‘actions’] = StructNew() />
<cfdirectory action=”list” directory=”#expandPath(‘.’)#”
name=”totalCFCs” filter=”*.cfc” recurse=”false” />
<cfloop query=”totalCFCs”>
<cfset cfcName = ListFirst(totalCFCs.name, ‘.’) />
<cfset newCfComponentMeta = GetComponentMetaData(cfcName) />
<cfif StructKeyExists(newCfComponentMeta, “ExtDirect”)>
<cfset CFCApi = ArrayNew(1) />
<cfset fnLen = ArrayLen(newCFComponentMeta.Functions) />
<cfloop from=”1″ to=”#fnLen#” index=”i”>
<cfset currFn = newCfComponentMeta.Functions[i] />
<cfif StructKeyExists(currFn, “ExtDirect”)>
<cfset Fn = StructNew() />
<cfset Fn[‘name’] = currFn.Name/>
<cfset Fn[‘len’] = ArrayLen(currFn.Parameters) />
<cfif StructKeyExists(currFn, “ExtFormHandler”)>
<cfset Fn[‘formHandler’] = true />
</cfif>
<cfset ArrayAppend(CFCApi, Fn) />
</cfif>
</cfloop>
<cfset jsonPacket[‘actions’][cfcName] = CFCApi />
</cfif>
</cfloop>
<cfoutput><cfsavecontent variable=”script”>Ext.ns(‘#arguments.
ns#’);#arguments.ns#.#desc# = #SerializeJson(jsonPacket)#;</
cfsavecontent></cfoutput>
<cfreturn script />
</cffunction>


The getAPIScript method sets a few variables (including the ‘actions‘ array), pulls a listing of all ColdFusion Components from the directory, loops over that listing, and finds any components containing “ExtDirect” in their root meta. With every component that does contain that meta, it then loops over each method, finds methods with “ExtDirect” in the function meta, and creates a structure with the function name and number of arguments, which is then added to an array of methods. When all methods have been introspected, the array of methods is added to the ‘actions‘ array. Once all ColdFusion Components have been introspected, the entire packet is serialized into JSON, and returned to API.cfm for output.

One item to note is that the script, when introspecting method metadata, also looks for a “ExtFormHandler” attribute. If it finds the attribute, it will include that in the method struct prior to placing the struct in the ‘actions‘ array.

LEAVE A REPLY

Please enter your comment!
Please enter your name here