Skip to content
This repository has been archived by the owner on Dec 30, 2024. It is now read-only.

Working with RestfulX Service Providers

dima edited this page Aug 14, 2010 · 2 revisions

Service Providers are at the core of the RESTful contract between External Services (such as Rails or Merb back-end or local SQLite database) and your application. Most of the time they are invisible in your normal development process. Probably the only time you’ll hit them is when you initialize your ApplicationController and even then only if you want to use something other than the default XML-over-HTTP provider.

However, it’s still important to understand what Service Providers are available and what you need to do to switch between them.

Application Initialization

RestfulX-based Flex/AIR apps typically instantiate central ApplicationController on startup.


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()">
  <mx:Script>
    <![CDATA[
      import pomodo.controllers.ApplicationController;

      private function init():void {
        ApplicationController.initialize();
      }
    ]]>
  </mx:Script>
</mx:Application>

Although it doesn’t look like it, there’s actually a default Service Provider getting instantiated as a result of ApplicationController.initialize() call. That Service Provider is XMLHTTPServiceProvider. As the name suggests, this provider messages XML between server and your Application using Adobe’s HTTPService implementation. It takes care of all low level asynchronous communication details, sets up relevant URLs, and performs appropriate CRUD/REST actions. It also knows to do the right thing when your model has binary attachments (e.g. a Picture) or it doesn’t.

If we wanted to be specific we could initialize the Application above as follows:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()">
  <mx:Script>
    <![CDATA[
      import org.restfulx.services.http.XMLHTTPServiceProvider;
      import pomodo.controllers.ApplicationController;

      private function init():void {
        ApplicationController.initialize([], XMLHTTPServiceProvider.ID);
      }
    ]]>
  </mx:Script>
</mx:Application>

The first argument to initialize is an array of extra Service Provider classes you may want instantiated, the second argument is the default Service Provider to use for all REST/CRUD invocations.

Why do we need extra provider classes array if we don’t use it? Most of the time you do actually use it. XMLHTTPServiceProvider happens to be the only provider that is instantiated by default. It is not however the only service provider available. If you want to use other Service Providers or perhaps develop your own to use your own messaging format or what have you. You’ll need to pass that provider in the extra services array.

Here’s an example of an AIR app initialization block that uses AIR SQLite Service Provider by default:


<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()">
  <mx:Script>
    <![CDATA[
      import org.restfulx.services.air.AIRServiceProvider;
      import pomodo.controllers.ApplicationController;

      private function init():void {
        ApplicationController.initialize([AIRServiceProvider], AIRServiceProvider.ID, "pomodo");
      }
    ]]>
  </mx:Script>
</mx:WindowedApplication>

Why don’t we just initialize all available providers by default? First of all, we won’t necessarily be able to do that. AIRServiceProvider for example depends on classes that are only available to AIR applications. That is to say you won’t be able to use it in your Flex application. The other reason is that we don’t want classes that are not actually used to be compiled into your Application. The fewer classes we compile in, the faster your application will load. So it pays to keep your services provider array small and only compile in what you are going to use.

Available Service Providers

  • XMLHTTPServiceProvider: Digests XML formatted messages. See RestfulX XML-over-HTTP Provider API for API details. Note, Since Adobe’s default HTTPService implementation doesn’t support HTTP DELETE or HTTP PUT create and update calls are actually made using application/form-url-encoded format. This simulates a regular HTML form-type submission. Server responses are expected to be in (f)XML however.
  • JSONHTTPServiceProvider: Digests JSON formatted messages. The same caveat about create and update calls applies because this provider is also based on default HTTPService implementation.
  • AIRServiceProvider: Implements REST/CRUD methods for local SQLite database, persists RestfulX Models and converts all relevant operations into SQLite compatible SQL queries.
  • AS3XMLHTTPServiceProvider: Receives and sends XML formatted messages. Based on the as3httpclient HTTP implementation, which does implement HTTP DELETE and HTTP PUT primitives. This service provider operates purely in XML. Why would we not use this by default? This introduces a dependency on external library, which would increase your application size. Use this if you absolutely must communicate using XML only or you need HTTPS support.
  • AS3JSONHTTPServiceProvider: Receives and sends JSON formatted messages. Like the provider above uses as3httpclient implementation. Use this if you want to message JSON and you need HTTPS support.
  • MockXMLHTTPServiceProvider: This service provider simply mocks all requests against an in-memory database (dictionary) of available models that you have to pre-populate if you expect Rx.models.index against this provider to return anything. Use this for testing or for creating fully-independent demo apps that you can pass on to your designer/UI developer to style. While you work on the back-end/data integration.
  • DirectCouchDBHTTPServiceProvider: Eliminates the need for a server. Allows you to perform RESTful CRUD against a CouchDB server directly from your Flex/AIR application. Based on as3httpclient.
  • GAEHTTPServiceProvider: Implements access to the Google App Engine back-end. This is based on XMLHTTPServiceProvider but uses GAE specific serializer.

Mixing and Matching Service Providers

It is entirely possible to instantiate multiple services providers, use any one of them by default but use a different one for a specific call or change default service provider at runtime. Here’s an example. Let’s say you want to use XMLHTTPServiceProvider by default but you also want to mirror all models that make it into the cache into your local AIR SQLite database. Here’s what you can do:


<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()">
  <mx:Script>
    <![CDATA[
      import org.restfulx.services.air.AIRServiceProvider;
      import org.restfulx.services.http.XMLHTTPServiceProvider;
      import org.restfulx.events.CacheUpdateEvent;
      import org.restfulx.Rx;
      import pomodo.controllers.ApplicationController;

      private function init():void {
        ApplicationController.initialize([AIRServiceProvider], XMLHTTPServiceProvider.ID, "pomodo");
        Rx.models.addEventListener(CacheUpdateEvent.ID, onCacheUpdate);
      }

      private function onCacheUpdate(event:CacheUpdateEvent):void {
        for each (var instance:Object in Rx.models.cache.data[event.fqn]) {
          Rx.services.getServiceProvider(AIRServiceProvider.ID).create(instance, null);
        }
      }
    ]]>
  </mx:Script>
</mx:WindowedApplication>

This will take the stuff from cache as it arrives via XMLHTTPServiceProvider and save all of it to your local SQLite database, so that you can switch to SQLite later, e.g. when the user goes offline.

Dynamically changing default Service Provider


// anywhere in your AS3/MXML code
Rx.defaultServiceId = JSONHTTPServiceProvider.ID # or any other provider

Setting Service Provider on a per-method call basis


project.create({targetServiceId: JSONHTTPServiceProvider.ID});

This will use JSONHTTPServiceProvider for this one call but will leave default service provider the same.

All REST/CRUD methods such as index, show, create, etc accept {targetServiceId:<YourServiceProvider>.ID} option.