Sencha Inc. | HTML5 Apps

Ext Direct

Ext Direct

Ext Direct is a platform and language agnostic technology to remote server-side methods to the client-side. Ext Direct allows for seamless communication between the client-side of an Ext JS application and all popular server platforms.

Optional Features

There are many optional pieces of functionality in the Ext Direct specification. The implementor of each server-side implementation can include or exclude these features at their own discretion. Some features are not required for particular languages or may lack the features required to implement the optional functionality.

  • Remoting methods by metadata – Custom annotations and attributes
  • Programmatic, JSON or XML configuration
  • Type conversion
  • Asynchronous method calls
  • Method batching
  • File uploading
  • Specify before and after actions to execute allowing for aspect oriented programming. This is a powerful concept which can be used for many uses such as security.

Server Platforms

Each Server-side Stack requires the following 3 key components in order to perform remoting of methods.

  • Configuration – To specify which components should be exposed to the client-side
  • API – To take the configuration and generate a client-side descriptor
  • Router – To route requests to appropriate classes, components or functions

Configuration

There are 4 typical ways that a server-side will denote what classes need to be exposed to the client-side. These are Programmatic, JSON, XML configurations and metadata.

Languages which have the ability to do dynamic introspection at runtime may require less information about the methods to be exposed because they can dynamically determine this information at runtime.

Some language specific considerations:

  • Ability to make an argument optional
  • Ability to dynamically introspect methods at runtime
  • Ability to associate metadata with classes or methods
  • Requirement to specify how many arguments each method will receive (Currently required in Ext Direct)
  • Ability to specify named arguments to pass an argument collection. When using an argument collection order of the arguments does not matter. (Not currently supported in Ext Direct)
  • Different languages may require different ways of describe their server-side methods. What may work for one language will may not be enough information the other. The important outcome of the configuration is to describe the methods that need to be remotable, their arguments and how to execute them.

Programmatic Configurations

Programmatic configuration builds the configuration by simply creating key/value pairs in the native language. (Key-Value Data Structures are known by many names: HashMap, Dictionary, Associative Array, Structure, Object). Please use the term which feels most natural to the server-side of your choice.

 
$API = array(
  "AlbumList"=>array(
      "methods"=>array(
          "getAll"=>array(
              "len"=>0
          ),
          "add"=>array(
              "len"=>1
          )
      )
  )
);
 

Here we are instructing the server-side that we will be exposing 2 methods of the AlbumList class getAll and add. The getAll method does not accept any arguments and the add method accepts a single argument. The PHP implementation does not need to know any additional information about the arguments, their name, their type or their order. Other server-side implementations may need to know this information and will have to store it in the configuration.

JSON & XML Configuration

This configuration information could also be stored in a JSON or XML Configuration file on the file-system which is read-in and parsed.

JSON Configuration:

 
{
    AlbumList: {
        methods: {
            getAll: {
                len: 0
            },
            add: {
                len: 1
            }
        }
    }
}
 

XML Configuration:

 
<AlbumList>
    <methods>
        <method name="getAll" len="0" />
        <method name="add" len="1" />
    </methods>
</AlbumList>
 

Configuration By Metadata

Some server-side environments may require less information because they are able to dynamically introspect their methods at runtime. Consider this example of a ColdFusion component which has a custom attribute of ExtDirect in order to make it remotable.

 
<cfcomponent name="AlbumList" ExtDirect="true"></p>
    <cffunction name="getAll" ExtDirect="true">
        <cfreturn true />
    </cffunction>
    <cffunction name="add" ExtDirect="true">
        <cfargument name="album" />
        <cfreturn true />
    </cffunction>
</cffunction>
 

The ColdFusion Ext Direct stack is able to introspect this component and determine all of the information it needs to remote the component via this custom attribute.

API

The purpose of the API component of the Ext Direct stack is to output the method configurations for Ext Direct to create client-side stubs. By generating these proxy methods, we can seamlessly call server-side methods as if they were client-side methods without worrying about the interactions between the client and server-side.

The API component will be included via a script tag in the head of the application. The server-side will dynamically generate an actual JavaScript document to be executed on the client-side.

Api included via a script tag

 
<script src="Api.php"></script>
 

The JS will describe the methods which have been exposed by the configuration. The following example uses the variable name Ext.app.REMOTING_API. The description describes the URL, the type and available actions: Class and method.

JavaScript generated by Api.php (or appropriate server-side stack)

 
Ext.app.REMOTING_API = {
    "url":"remote\/router.php",
    "type":"remoting",
    "actions":{
        "AlbumList":[{
            "name":"getAll",
            "len":0
        },{
            "name":"add",
            "len":1
        }]
    }
};
 

Router

The router accepts requests from the client-side and routes them to the appropriate Class, method and passes the proper arguments.

Requests can be sent in two ways, via JSON-Encoded raw HTTP Post or a form post. When uploading files the form post method is required.

JSON-Encoded raw HTTP posts look like:

 
{<a href=""AlbumList","method":"getAll","data":[],"type":"rpc","tid":2">action</a>}
 

The router needs to decode the raw HTTP post. If the http POST is an array, the router is to dispatch multiple requests.

Each transaction can contain

  • action – The class to use
  • method – The method to execute
  • data – The arguments to be passed to the method – array (Ext Direct will support named arguments in the future and thefore an object literal here)
  • type – “rpc” for all remoting requests
  • tid – Transaction ID to associate with this request. If there are multiple transactions in a single POST these will be different.
  • Form posts will contain the following parameters.
  • extAction – The class to use
  • extMethod – The method to execute
  • extTID – Transaction ID to associate with this request. Form POSTs can only support a single transaction
  • extUpload – (optional) field is sent if the post is a file upload
  • Any additional form fields will be assumed to be arguments to be passed to the method.

Once a transaction has been accepted it must be dispatched by the router. The router must construct the relevant class and call the method with the appropriate arguments which it reads from data. Currently, the Ext Direct specification expects this to be an array. In the future, we plan to add support to be key/value pairs in an object.

Note At this point there is no mechanism to construct a class with arguments. It will only use the default constructor.

The response of each transaction should have the following attributes in a key-value pair data structure.

  • type – ‘rpc’
  • tid – The transaction id that has just been processed
  • action – The class/action that has just been processed
  • method – The method that has just been processed
  • result – The result of the method call
This response will be JSON encoded. The router can send back multiple transactions within a single response enclosed in an array.

If the request was a form post and it was an upload the response will be sent back as a valid html document with the following content:

 
<html><body><textarea>{YOUR JSON RESPONSE HERE}</textarea></body></html>
 

" must be back-slashed because the textarea will convert them to actual quotes. Therefore you must do a regular expression (/”/, ”\””)

The response will be encoded as JSON and be contained within the textarea.

Form Posts can only execute one method and do not support batching.

If an exception occurs on the server-side the router should also return the following error information when the router is in debugging mode.

  • type – ‘exception’
  • message – Message which helps the developer identify what error occurred on the server-side
  • where – Message which tells the developer where the error occurred on the server-side.

This exception handling within the router should have the ability to be turned on or off. This exception information should never be sent back to the client in a production environment because of security concerns.

Exceptions are meant for server-side exceptions. Not application level errors.

Client Side Portions of Ext Direct

To use Ext Direct on the client side you will need to add each provider by the variable name you used in the API.

Ext.Direct.addProvider(Ext.app.REMOTING_API);

After adding the provider all of your actions will exist in the global namespace. (By including a namespace configuration in the Api Descriptor, the actions can be namespaced.)

The client-side will now be able to call the exposed methods as if they were on the server-side.

  • AlbumList.getAll
  • AlbumList.add

An additional argument will be added to the end of the arguments allowing the developer to specify a callback method. Because these methods will be executed asynchronously it is important to note that we must use the callback to process the response. We will not get the response back immediately.

For example we do not want to do this:

 
var albums = AlbumList.getAll();
 

This code should be written like this:

 
AlbumList.getAll(function(provider, response) {
   // process response
});