Single Page Apps – Retrieving, Caching Server Requests Using AmplifyJS

image8You may want to use storage to store data. You can save the data your user has entered in a wizard. Or you might want to save data so you can provide an offline experience. Or you may want to store user preferences. Local storage is a good idea anytime you do not want, or need your user or your application to start all over.

AmplifyJS is a very neat library that provides a consistent API to handle client storage that works in most browsers.

In this post, you will learn to retrieve the data through amplify.request without concern for data caching, server interface, resource location, data types, wrappers, and all the other specificities of the client/server interaction.

Requests made through amplify.request will always be resolved asynchronously, even if the resource invokes the callbacks immediately.

You will probably need jQuery for Amplify Request. The default request type shipped with AmplifyJS does utilize jQuery AJAX, but you can just as easily create a new request type that uses Dojo, MooTools, etc.

However the publish/subscribe and store components do not use jQuery at all.

In a previous post, you learned how to get started by using Amplify store. In this, you’ll learn how to request data from the server.

Amplify Data Request

amplify.request is an abstraction layer that can be used for any kind of request for data. amplify.request sets out to separate the data retrieval and caching mechanisms from data requestors.

The request is built in two steps. The first step you define the request, and the later in your code, you can request the data.

Define Request

When defining an ajax request, you can provide data in the definition. You you can create and maintain your entire server interface and caching policy in a single place, reducing the impact of any server interface changes using amplify.request.define.

This data will be merged (via a deep extend) with any data provided with the request. Data provided with the request itself will override data provided in the definition.

For example, you can set up the request by defining a request such as the following:


amplify.request.define("easyData", "ajax", {
url: "Data/easydata.txt",
dataType: "json",
type: "GET"
});

easyData is the resourceId that you will use in your code for subsequent requests using this definition. The url, dataType, and type are passed to the jQuery.ajax command, that was specified in the second parameter, ajax. That means you can specify any the parameters you need for jQuery using this definition.

Request the Data

Once you have a request definition, you can request the data. Pass in:

  • resourceId. A string you provide to identify the resource.
  • data. This is optional key/value pairs that may be sent to the server.
  • callback. A function to invoke if the data is successfully retrieved.

The following example retrieves a simple JSON file using the definition in the previous section.


$("#productsClick").click(function (eventData) {
// Retrieves data from server
amplify.request("easyData", function (data) {
$("#products").text(data.products).show();
});
});

Amplify Request Data Sample

Here is a some short sample data that we can retrieve from a file named easydata.txt in the data folder.

Data/easydata.txt


{
"products" : "Toys",
"brand" : "Toys For Kids"
}

Here is the sample that shows how you can retrieve data.


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
<title>Store and Brand</title>
</head>
<body>
<h3>Click for Store and Brand</h3>
<p id="products"></p>
<p>Watch for server hits in the developer panel</p>
<input id="productsClick" type="button" value="Click to get products" />
<script src="Scripts/jquery-1.4.4.js"></script>
<script src="Scripts/amplify.js"></script>
<script>
amplify.request.define("easyData", "ajax", {
url: "Data/easydata.txt",
dataType: "json",
type: "GET"
});
$("#products").hide();
$("#productsClick").click(function (eventData) {
// first call retrieves data from server
amplify.request("easyData", function (data) {
$("#products").text(data.products).show();
});
});
</script>
</body>
</html>

Error Handling in the Data Request

You can define success and error handling in your amplify.request method.

amplify.request comes with built in support for status. The status parameter appears in the default success or error callbacks when using an ajax definition.

With the success callback, the only default status is success. With the error callback two default statuses are possible: error and abort.


amplify.request({
resourceId: "easyData",
success: function (data, status) {
$("#products").text(data.products).show();
},
error: function (data, status) {
if (status === "abort") {
console.log("loading aborted");
}
else {
console.log("error loading products " + status);
}
}
});

With the success callback, the only default status is success. With the error callback two default statuses are possible: error and abort.

A request is aborted by using the object returned by a request call:

// sometime later in code
  myRequest.abort();

Cached Request

Next, you can cache the request so that it can be reused by other objects. You can add the parameters to the definition file that can include storage in a built-in memory cache. You can:

  • Add cache: “true” to the request definition to cache the data for the rest of the page load.
  • Add cache: “persist” to the request definition to cache in the default store or you can specify any of the specific stores available, cache: “localStorage”. Once you do that, you can also cache the data using a pre-defined caching mechanism for the specified number of milliseconds.

 

Example of a definition file that caches the data for the rest of the page load.

amplify.request.define("easyData", "ajax", {
  url: "Data/easydata.text",
  dataType: "json",
  type: "GET",
  // Cache the data in memory for the remainder of this page load
  cache: true
});

Example of a definition file that caches the data into the local data store.

amplify.request.define("easyData", "ajax", {
  url: "Data/easydata.text",
  dataType: "json",
  type: "GET",
  // Cache the data in memory for the remainder of this page load
  cache: "persist"
});

Then in your code, the first time you call amply.request with a matching resourceId, you will retrieve the data from the server. The second time, you will retrieve it from the cache.

// first call retrieves data from server
amplify.request("easyData", function (data) {
  $("#products").text(data.products).show();
});

// second call retrieves data from cache
amplify.request("easyData", function (data) {
  $("#brand").text(data.brand).show();
});

See the documentation for how you can create your own Amplify custom caches.

Sample of Cached Requests Using Amplify

When you run this in the browser, watch the Network tab and see when the data is retrieved. And this time, you will fade in the data, whether it comes from cache or from a server retrieval.


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
<title>Store and Brand</title>
</head>
<body>
<h3>Click for Store and Brand</h3>
<p id="products"></p>
<p id="brand"></p>
<p>Watch for server hits in the developer panel</p>
<input id="productsClick" type="button" value="Click to get products" />
<input id="brandClick" type="button" value="Click to get brand" />
<script src="Scripts/jquery-1.4.4.js"></script>
<script src="Scripts/amplify.js"></script>
<script>
amplify.request.define("easyData", "ajax", {
url: "Data/easydata.txt",
dataType: "json",
type: "GET",
// Cache the data in local storage
cache: "persist",
});
$("#products").hide();
$("#brand").hide();
$("#productsClick").click(function (eventData) {
// first call retrieves data from server
amplify.request({
resourceId: "easyData",
success: function (data) {
$("#products").hide();
$("#products").text(data.products).fadeIn("slow");
},
error: function (data, status) {
errorLoading("products", data, status);
}
});
});
$("#brandClick").click(function (eventData) {
// a second call will result in retrieving from
// the cache, rather than making a call to the server
amplify.request({
resourceId: "easyData",
success: function (data) {
$("#brand").hide();
$("#brand").text(data.brand).fadeIn("slow");
},
error: function (data, status) {
errorLoading("brand", data, status);
}
});
});
function errorLoading(location, data, status) {
console.log("error loading " + location);
}
</script>
</body>
</html>

RESTful Requests

In a following post, you’ll learn how to use Amplify with Sammy to pass in restful requests. But as a quick preview, the Amplify portion is defining a URL with parameters, and then passing those parameters into the request.

Here’s a quick preview as shown on the Amplify documentation.


amplify.request.define( "ajaxRESTFulExample", "ajax", {
url: "/myRestFulApi/{type}/{id}",
type: "GET"
})
// later in code
amplify.request( "ajaxRESTFulExample",
{
type: "foo",
id: "bar"
},
function( data ) {
// /myRESTFulApi/foo/bar was the URL used
data.foo; // bar
}
);

Code Sample

A complete code sample for Amplify can be found in the DevDays repository on GitHub: https://github.com/devdays/single-page-app/tree/master/Amplify

References