-
Notifications
You must be signed in to change notification settings - Fork 62
Working with RestfulX Service Providers
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.
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.
-
XMLHTTPServiceProvider
: Digests XML formatted messages. See RestfulX XML-over-HTTP Provider API for API details. Note, Since Adobe’s default HTTPService implementation doesn’t supportHTTP DELETE
orHTTP PUT
create
andupdate
calls are actually made usingapplication/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 aboutcreate
andupdate
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 theas3httpclient
HTTP implementation, which does implementHTTP DELETE
andHTTP 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 usesas3httpclient
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 expectRx.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 onas3httpclient
.
-
GAEHTTPServiceProvider
: Implements access to the Google App Engine back-end. This is based on XMLHTTPServiceProvider but uses GAE specific serializer.
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.
// anywhere in your AS3/MXML code
Rx.defaultServiceId = JSONHTTPServiceProvider.ID # or any other provider
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.