A promised-based interface for isomoprhic resources with built-in caching.
Resourceful implements a simple respository interface for querying data in universal code. Implementation details are abstracted away from the comsumer so that the appropriate type of resource (e.g. XHR, DB, FS) may be injected into an arbitrary universal code (typically something that depends on the same data model on both the client and server) without affecting integration code.
Resourceful allows you to create individual "resource" instances, each one providing a common promise-based-interface for a particular data type and source.
Currently, the following integrations exist:
A client-side resource for querying JSON over an API using XHR.
A server-side resource for querying MongoDB documents via Mongoose ODM.
A server-side resource for querying all files of a type or one specific file in a file-system directory.
Additionally, an abstract ResourceBase
class, and the public interface IResource
are provided so that new integrations can be to be added with ease.
The IResource
interface implements the following API methods, which all resource integrations must expose.
.get(query[, req][, res])
Type | Name | Description | |
---|---|---|---|
param | object |
query | A query object containing one or more key value pairs |
param | object |
[req] | An optional request object to passed to the underlying implementation (e.g. for authentication) |
param | object |
[res] | An optional response object to be passed to the underlying implementation (e.g. for authentication) |
return | Promise.<Array.<object>> |
A list of entries matching the query |
Returns a Promise resolving with a list of entries matching the provided query.
.getOne(query[, req][, res])
Type | Name | Description | |
---|---|---|---|
param | object |
query | A query object containing one or more key value pairs |
param | object |
[req] | An optional request object to passed to the underlying implementation (e.g. for authentication) |
param | object |
[res] | An optional response object to be passed to the underlying implementation (e.g. for authentication) |
return | Promise.<Array.<(object,null)>> |
An entry matching the query or null |
Returns a Promise resolving with a single entry matching the provided query, or null
if none found. This is a shorthand for .get()[0]
, and can be used when querying by a unique ID.
.create(payload)
Type | Name | Description | |
---|---|---|---|
param | object |
payload | An object containing the data to be created |
return | Promise.<object> |
The newly created item |
Creates an entry and returns a promise resolving with that new entry on success.
.update(query, payload)
Type | Name | Description | |
---|---|---|---|
param | object |
query | A query object typically containing a single key value pair to match an item's unique ID |
param | object |
payload | An object containing the data to be created |
return | Promise.<object> |
The newly created item |
Updates an existing entry (by query) and returns a promise resolving with that updated entry on success.
.delete(query)
Type | Name | Description | |
---|---|---|---|
param | object |
query | A query object typically containing a single key value pair to match an item's unique ID |
return | Promise.<object> |
The deleted item |
Deletes an existing entry (by query) and returns a promise resolving with that deleted entry on success.
.flushCacheStore(query)
Type | Name | Description | |
---|---|---|---|
param | object |
query | A query object containing one or more key value pairs |
return | void |
Deletes one or more entries from the cache matching the provided query.
.flushCache()
Type | Name | Description | |
---|---|---|---|
return | void |
Deletes the resource's entire cache
Each resource type follows the same basic pattern for instantiation.
A typical client-side resource file might look like the following:
import {ResourceXHR} from 'resourceful';
const people = new ResourceXHR({
// configuration options
});
export default people;
And its server-side equivalent:
import {ResourceMongoose} from 'resourceful';
const people = new ResourceMongoose({
// congiguration options
});
export default people;
As above, it is very common for resources to be defined in pairs, so that the appropriate resource can be easily injected into universal code regardless of its type, and will yield identical results when called.
The only difference in the above two options would be the configuration.
In our universal code, we may then interact with a people resource using the exact same syntax regardless of environment. Imagine the following class:
class PeopleManager() {
constructor(resource) {
// A people resource of abitrary type is injected on instantiation
this.resource = resource;
}
/**
* @return {Promise.<Array.<object>>}
*/
findBosses() {
return this.resource.get({
type: 'boss'
});
}
/**
* @param {string} name
* @return {Promise.<object>}
*/
createBoss(name) {
const boss = {
type: 'boss',
name: name
};
if (!name || typeof name !== string) {
throw new TypeError('No valid name provided');
}
return this.resource.create(boss);
}
}
All resource types implement the common configuration options shown below. In addition to these, implementation specific configuration options exist for each type of integration. These can be found in the integration specific documentation which is linked to in the Integrations section above.
Config {
cache: {
enable: true,
primaryKey: '',
secondaryKeys: []
},
data: {
init: null,
Model: null
},
transform: {
query: null,
response: null,
entry: null,
error: null
}
}
A resource can be configured by passing zero or more configuration options as follows, with all options falling back to the defaults shown above if not specified.
const people = new ResourceXhr({
xhr: {
path: '/api/v2.0/people/'
},
cache: {
primaryKey: 'id'
},
transform: {
response: response => response.items,
error: response => response.errors
}
});
Each option is described in detail below.
NB: the xhr
configuration options shown in the above example are specific to the ResourceXHR
type and are therefore not described below but covered in the relevent document.
A collection of options relating to a resource's internal cache.
enable
A boolean dictating whether or not caching should be enabled for the resource.
Type | Default |
---|---|
boolean |
true |
primaryKey
An optional unique primary key present in all items to cache by. When a list of matching entries is returned by a non unique query, each one may then be cached individually by a unique ID for fast lookup at a later time.
Type | Default |
---|---|
string |
'' |
secondaryKeys
As above, but allows multiple secondary keys to be specified.
Type | Default |
---|---|
Array.<string> |
[] |
A collection of options relating to data contained by the resource.
init
An optional array of entries or "init data" to be provided to the resource on instantiation, matching the expected first request to the resource. This can be useful in a client side resource, where its first query may be to fetch something that is already available (for example, via a server-rendered document), and thus prevents an uneccessary API call.
Type | Default |
---|---|
Array.<object> |
[] |
Model
An optional class or constructor function used to coerce data into a custom model before being returned to the consumer. When provided, data is still cached in its raw form, and coerced only upon request. This is particularly useful when virtual properties are needed on an object (e.g. a fullName
, property combining firstName
and lastName
).
Type | Default |
---|---|
function |
null |
A collection of optional data transform functions. Functions may be syncronous, or promise-returning asyncronous functions, allowing for the plugging in of calls to other resources in order to map in additional data to an object before being returned to the consumer.
All functions receive the relevant object as their parameter, and must return an equivalent object, or a Promise resolving with that object.
query
A function allowing transformation of the provided query before it hits the integration.
Type | Default |
---|---|
function |
null |
response
A function allowing transformation of an integration's response, before it is written to cache and returned by the resource.
Type | Default |
---|---|
function |
null |
entry
A function allowing transformation of an entry, after it has been cached, but before it is returned by the resource.
Type | Default |
---|---|
function |
null |
error
A function allowing transformation of an integration's error response (e.g. an API's 500
status), into an array or one or more errors to be passed back to the consumer.
Type | Default |
---|---|
function |
null |
© 2017 Patrick Kunka / KunkaLabs Ltd