Consuming Web Services - accountforgithub/enyo GitHub Wiki
In this article, we look at how the Enyo framework enables apps to work with services in general, and Web services in particular.
In Enyo, Web requests are made using either the
enyo.Ajax object or the
enyo.WebService component.
enyo.Ajax derives directly from enyo.Async,
the base kind for handling asynchronous operations. enyo.WebService manages
HTTP transactions by using either enyo.Ajax or
enyo.JsonpRequest, which is
another subkind of enyo.Async.
Considering the central role of Async, it makes sense to begin our discussion
there.
enyo.Async, again, is a generalized kind for dealing with asynchronous transactions.
enyo.Async is an Object, not a Component; thus, you may not declare an
Async in a components block. If you want to use Async as a component, you
should probably be using enyo.WebService
instead. (See the section on WebService below.)
An Async object represents a task that has not yet completed. You may attach callback functions to an Async, to be called when the task completes or encounters an error.
To use an Async, create a new instance of enyo.Async or a kind derived from
it, then register handlers in the response and error methods.
Start the asynchronous operation by calling the go method.
Handlers may either be methods with the signature (asyncObject, value) or new
instances of enyo.Async or its subkinds. This allows for chaining of Async
objects (e.g., when calling a Web API).
If a response method returns a value (other than undefined), that value is sent to subsequent handlers in the chain, replacing the original value.
A failure method may call recover to undo the error condition and switch
to calling response methods.
The default implementation of go causes all the response handlers to be called
(asynchronously).
The following (rather complicated) example demonstrates many of the aforementioned features:
var transaction = function() {
// Create a transaction object.
var async = new enyo.Async();
// Cause handlers to fire asynchronously (sometime after we yield this thread).
// "initial response" will be sent to handlers as inResponse
async.go("intial response");
// Until we yield the thread, we can continue to add handlers.
async.response(function(inSender, inResponse) {
console.log("first response: returning a string,",
"subsequent handlers receive this value for 'inResponse'");
return "some response";
});
return async;
};
Users of the transaction function may add handlers to the Async object
until all functions return (synchronously):
// Get a new transaction; it's been started, but we can add more handlers
// synchronously.
var x = transaction();
// Add a handler that will be called if an error is detected. This handler
// recovers and sends a custom message.
x.error(function(inSender, inResponse) {
console.log("error: calling recover", inResponse);
this.recover();
return "recovered message";
});
// Add a response handler that halts response handler and triggers the
// error chain. The error will be sent to the error handler registered
// above, which will restart the handler chain.
x.response(function(inSender, inResponse) {
console.log("response: calling fail");
this.fail(inResponse);
});
// Recovered message will end up here.
x.response(function(inSender, inResponse) {
console.log("response: ", inResponse);
});
enyo.Ajax extends enyo.Async, providing a
wrapper for JavaScript's XmlHttpRequest (XHR) API.
enyo.Ajax publishes all the properties of the
enyo.AjaxProperties object. You may
set values for these properties to customize different aspects of your HTTP
request, such as the url, method, optional headers, and username and password
for authentication.
Like enyo.Async, enyo.Ajax is an Object, not a Component. Do not try to
make enyo.Ajax objects inside a components block.
Also like enyo.Async, if you find yourself wanting to use enyo.Ajax as a
component, you should probably be using WebService instead. (By default,
WebService uses enyo.Ajax internally to manage HTTP transactions.)
The following example uses enyo.Ajax to retrieve a unique id from Yahoo!
corresponding to the passed-in place name:
getWoeid: function(inPlace) {
// set up enyo.AjaxProperties by sending them to the enyo.Ajax constructor
var x = new enyo.Ajax({url: "http://query.yahooapis.com/v1/public/yql?format=json"});
// send parameters the remote service using the 'go()' method
x.go({
q: 'select woeid from geo.placefinder where text="' + inPlace + '"'
});
// attach responders to the transaction object
x.response(this, function(inSender, inResponse) {
// extra information from response object
var woeid = inResponse.data.query.results.Result.woeid;
// do something with it
this.setWoeid(inPlace, woeid);
};
}
For additional examples of enyo.Ajax in action, look under
"Enyo Core > Ajax" in the Sampler app on
enyojs.com. (The Sampler also has examples using JsonpRequest and
WebService.)
enyo.JsonpRequest is a specialized
form of enyo.Async used for making JSONP requests to a remote server (which
must, of course, support such requests). This differs from the normal
XmlHttpRequest call in that the external resource is loaded using a <script>
tag.
enyo.JsonpRequest is useful when an application needs to load data from a
different domain. JSONP lets us work around the browser security model for
cross-origin requests, in which cross-origin XHRs can only be made to the same
server the page is loaded from (unless the server supports cross-origin
resource sharing, aka "CORS"). In a JSONP request, this restriction does not
come into play because a browser will load scripts from any address.
In addition to using enyo.JsonpRequest directly, you can make a JSONP request
using WebService by setting jsonp to true on the WebService instance.
When you do this, WebService will use enyo.JsonpRequest internally to manage
the HTTP transaction.
enyo.WebService is a component that
performs XHR requests; it acts as a wrapper for the Async subkinds enyo.Ajax
and enyo.JsonpRequest, using these subkinds internally to manage HTTP
transactions.
enyo.WebService uses enyo.Ajax by default and, like enyo.Ajax, it
publishes all the properties of the
enyo.AjaxProperties object. You may
customize your HTTP request by setting values for these properties on a given
WebService instance.
To have a WebService instance use enyo.JsonpRequest instead of enyo.Ajax,
set "jsonp: true" on the instance.
The send method sends the request, returning the Async instance used. The
response data comes in the data field of an incoming onResponse or onError
event object.
By this point, you may have noticed that there is a lot of overlap in what
enyo.WebService and enyo.Ajax can do. In general, we recommend using
enyo.Ajax, as it has the advantage of not needing to be declared as a
component. However, enyo.WebService works better if you want to declare your
AJAX endpoints as part of the components block.