REST (Representational State Transfer)¶
qx.io.rest.Resource allows to encapsulate the specifics of a REST interface. Rather than requesting URLs with a specific HTTP method manually, a resource representing the remote resource is instantiated and actions are invoked on this resource. A resource with its actions can be configured declaratively or programmatically.
Note
When to use qx.bom.rest.Resource? Mostly qx.io.rest.Resource delegates to qx.bom.rest.Resource and adds some features on top. For qx.Desktop apps you probably want to use qx.io.rest.Resource but when developing an app/website with qx.Website only qx.bom.rest.Resource is available (i.e. exposed as website module).
See the package description for a detailed comparison: qx.bom.rest .
Configuring actions¶
Given a REST-like interface with URLs that comply to the following pattern.
GET /photo/{id}
PUT /photo/{id}
DELETE /photo/{id}
GET /photos
POST /photos
Note {id} stands for a placeholder.
This interface comprises of two resources: photo and photos.
To declare the specifics of the REST interface declaratively, pass a description to the constructor.
// Singular resource
var photo = new qx.io.rest.Resource({
// Retrieve photo
get: {
method: "GET",
url: "/photo/{id}"
},
// Update photo
put: {
method: "POST",
url: "/photo/{id}"
},
// Delete photo
del: {
method: "DELETE",
url: "/photo/{id}"
}
});
// Plural resource
var photos = new qx.io.rest.Resource({
// Retrieve list of photos
get: {
method: "GET",
url: "/photos"
},
// Create photo
post: {
method: "POST",
url: "/photos"
}
});
Or programmatically, for each action.
var photo = new qx.io.rest.Resource();
photo.map("get", "GET", "/photo/{id}");
Invoking actions¶
Once configured, actions can be invoked. They are invoked by calling a method that is dynamically added to the resource on configuration of the action.
photo.get({id: 1});
// Alternatively: photo.invoke("get", {id: 1});
// --> GET /photo/1
photos.get();
// Alternatively: photos.invoke("get");
// --> GET /photos
When an action is invoked, an appropriate request is configured and send automatically.
Parameters¶
If the URL contains parameters, the position where the parameters should be inserted can be specified by using URI templates. Parameters are optional unless a check is defined. A default value can be provided.
var photo = new qx.io.rest.Resource();
photo.map("get", "GET", "/photo/{id}/{size=medium}", {id: qx.io.rest.Resource.REQUIRED});
photo.get({id: 1, size: "large"});
// --> GET /photo/1/large
photo.get({id: 1});
// --> GET /photo/1/medium
photo.get();
// --> Error: Missing parameter 'id'
Data¶
Data that should be included in the request's body can be given as second parameter. All types accepted by qx.io.request.AbstractRequest#requestData are supported.
photo.put({id: 1}, {title: "Monkey"}); // URL encoded
photo.put({id: 1}, "title=monkey"); // Raw
Note that the behavior changes when the request body content type is switched to application/json.
photos.configureRequest(function(req) {
req.setRequestHeader("Content-Type", "application/json");
});
photos.map("post", "POST", "/photos/{id}");
photos.post({id: 1}, {location: "Karlsruhe"}); // JSON.stringify
Events¶
Events are fired by the resource when the request was successful or any kind of error occurred. There are general resource events and action specific events. Handlers receive a qx.event.type.Rest event that, among other properties, includes the response.
photo.get({id: 1});
photo.put({id: 1});
// "success" is fired when any request associated to resource receives a response
photos.addListener("success", function(e) {
e.getAction();
// --> "get" or "put"
});
// "getSuccess" is fired when the request associated to the get action receives a response
photos.addListener("getSuccess", function(e) {
e.getAction();
// --> "get"
});
If the same action should be invoked multiple times and the events fired for each request be handled differently, it is possible to remember the id of the action's invocation. The Rest event includes this id.
var getPhotoId = photo.get({id: 1});
var getLargePhotoId = photo.get({id: 1, size: "large"});
photo.addListener("getSuccess", function(e) {
if (e.getId() === getLargePhotoId) {
// Handle large photo
}
});
Helpers¶
Helpers make it easy to accomplish common tasks when working with requests.
- refresh(action) Resend request associated to action. Uses parameters given before.
- poll(action, params) Periodically invoke action.
- longPoll(action) Use Ajax long-polling to update whenever new data is available.
Data binding¶
A qx.data.store.Rest store can be attached to an action. Whenever a response is received, the model property of the store is updated with the marshaled response.
var store = new qx.data.store.Rest(photos, "get");
var list = new qx.ui.form.List();
var controller = new qx.data.controller.List(null, list);
store.bind("model", controller, "model");
photos.longPoll("get");