Falcor Part 1
I’ve been looking at Neflix’s falcor it’s an attempt to solve one of the problems with REST APIs which is to do with granularity. When creating an application you often want to work with resources at a highly granular level (individual properties) rather than in terms of whole documents and that for some operations you need information about many resources but you don’t want to make multiple calls accross the wire for the information from each resource.
A simple example might be that in your application you want to display a list of recent items with a title and a link.
GET /recent
[
{"id": 27, "title": "Foo"},
{"id": 38, "title": "Bar"},
{"id": 97, "title": "Baz"},
...
]
As an application evolves the requirements change - it may be that a thumbnail is needed too…
[
{"id": 27, "title": "Foo", "thumbnail": "/static/foo.jpg"},
{"id": 38, "title": "Bar", "thumbnail": "/static/bar.jpg"},
{"id": 97, "title": "Baz", "thumbnail": "/static/baz.jpg"},
...
]
And then the item owner’s wanted to be displayed as a tooltip (or some such).
Each time a feature is added the property needs adding to the endpoint - meaning extra backend development.
Then if the endpoint is used by multiple clients say web vs mobile where the amount of data needs to be reduced for bandwidth / machine capabilty a scheme might be added to specify which properties are wanted, this is not restful, creates complexity (different APIs have different schemes) and is again more backend work needed for new client code.
What falcor does is introduce a consistent scheme to facilate the access and manipulation of granular data trying not to throw the baby out with the bathwater in terms of keeping things cache friendly.
So here’s an example of how the initial query might be expressed using the falcor API on the client:
model.get('recent[0..5]["id","title"]')
.then(function(response) {
// work with the response...
});
We can see that we’ve been able to specify both a range query and which properties we want from the underlying object graph.
Back on the server there’s a router to which you add routes to deal with incoming queries, so for this route you’d add something like:
{
route: 'recent[{ranges}][{keys}]',
get: function(pathSet) {
var ranges = pathSet[1];
var props = pathSet[2];
...
}
}
Where the pathSet
looks like this:
[ "recent", [ { to: 5, from: 0 } ], [ "id", "title" ] ]
And so a more rich client such as a desktop could request:
get('recent[0..10]["id","title","thumbnail","author"]')
The same route in the API backend would match and be able to fulfil this request without changes.
What you’ll note here is that the actual resource that’s been recently used should live under a different route - such as items
by their ids - in Part 2 I’ll look into how this works.