@ra5mus/eb-datastore
v0.1.1
Published
Fetch-and-cache module designed to enable simple and flexible access to server-side APIs
Downloads
2
Readme
eb-datastore
The DataStore is both a way to handle network requests againts server-side APIs – and an offline cache on the user-side. It's AJAX, indexedDB and localStorage combined.
The cache will attempt to use indexedDB, but will degrade gracefully and fall back to using localStorage or no offline cache at all – as determined by the capabilities of the user's browser.
All fetch()
methods will return a Promise
object as a way of handling the asynchronous nature of both netowrking and indexedDB.
All watch()
methods till return an Observer
object, on which the method notify()
will be called, whenever the cached data expires and is refreshed automatically from the server-side state.
##Useage
The DS
object wrap the to main classes, API
and Endpoint
. the API
class is more of a convenience than anything else – a way of bundling multiple Endpoint
objects together, but Endpoint
objects can be used just fine on their own. There are even some convenience methods you can use directly on the DS module without instantiating anything, though they offer less flexibility.
Example using API class
var weatherAPI = new DS.API({
baseUrl: 'http://vejretapi.ekstrabladet.dk/v2/'
});
weatherAPI.defineEndpoint({
name:'weather',
url:'{baseUrl}weather/{geoid}[/{days}][/{intervals}]',
validfor: 10 * DS.MINUTES
});
weatherAPI.weather.fetch({
geoid: 2618425,
days: '1-7',
intervals: 24
}).then(function(data){
console.log(data);
});
Okay, so a few things are going on here, which we'll go through.
First we create an API
instance and add some properties to it – the most useful one will probably be baseUrl
, the naming is entirely optional as long as you're consistent.
Next we define an Endpoint
on our API
instance by way of the defineEndpoint
method. The properties name
and url
are mandatory while validfor
(which determines for how long the object will be cached on the client) will default to ten minutes if not specified. The url
property string is in a template format, which works much like other template strings – the curly braces contain variable names that will get replaced with values on initiating the network request. The variables come from the combined options of the call to fetch(options)
, the options given to the defineEndpoint
method AND the options from the initial instantiation of the API
object. Values in the fetch(options)
will overwrite those in the Endpoint
and API
, values in the Endpoint
will overwrite those in the API
. So in our case, the combined options are:
{
baseUrl: 'http://vejretapi.ekstrabladet.dk/v2/', // <-- weatherAPI
name: 'weather', // <-- weather Endpoint
url: '{baseUrl}weather/{geoid}[/{days}][/{intervals}]', // <-- weather Endpoint
validfor: 10 * DS.MINUTES, // <-- weather Endpoint
geoid: 2618425, // <-- call to fetch
days: '1-7', // <-- call to fetch
intervals: 24 // <-- call to fetch
}
So upon interpolation, the finished url will become:
http://vejretapi.ekstrabladet.dk/v2/weather/2618425/1-7/24
Now, the square brackets around some of the interpolation expressions, like [/{days}]
for instance, simply mean that if the days
variable cannot be resolved, everything in the scope of the square brackets will be omitted from the result. In this case it just means that the initial /
would also be omitted from the final url string. This is convenient in some apis.
The main advantage to using the API
class and adding Endpoint
objects to it via the defineEndpoint()
method is that the resulting weatherAPI
object becomes a single “thing” you can pass around inside your app – all the endpoints are accessible directly from this single object. You could have just as easily made a simple object like var a = {}
and added your endpoints directly to that, so using the API
class is just a convenience pattern.
Example using observe()
method
The DataStore also has a mechanism for polling the server for its current state. It's done almost identically to a fetch()
, but the returned object, instead of being a Promise
with a then()
method, it's an Observer
with a notify()
method. Basic Observer Pattern.
myObserver = weatherAPI.weather.observe({
geoid: 2618425,
days: 0,
intervals: 24,
validfor: 5 * DS.MINUTES
})
.notify(function(data){
// This is called everytime the data updates from
// the server. In this case every five minutes.
});