Restl - A hypermedia client for nodejs
Important note: this package is currently pretty experimental and not
complete. Use at your own risk.
Introduction
This NPM package is an attempt at creating a 'generic' hypermedia client, it
supports an opinionated set of modern features REST services might have.
This means that there's a strong focus on links and link-relationships.
Initially we'll build in strong support for Web Linking, a.k.a. the HTTP
Link
header, and HAL.
Installation
npm install --save restl
Goals
For 1.0:
- Expand CURIES automatically.
- Support HTTP
Link
header. - Support non-JSON resources, including things like images.
- Parse HTML5 links.
- Parse Atom.
- Built-in OAuth2.
Post 1.0
- Support for HAL Forms.
- Parse and respect HTTP Cache headers.
- Support
Prefer: return=representation
. - Browser support (nodejs only at the moment, but only because of the Request
library.)
- Unittests
Already done:
- Following links.
- Basic HAL parsing.
- Normalizing
_links
and _embedded
. PUT
request.DELETE
request.POST
request- Global resource cache.
- Resolve every URI to an absolute URI.
- Figuring caching resources from
_embedded
.
Usage
Fetching a resource and following a link:
var restl = require('restl')('http://my-hal-api.example.org/');
var home = restl.getResource()
home.follow('author')
.then(function(authorResource)) {
return authorResource.follow('me');
}.then(function(meResource) {
return meResource.get();
}.then(function(meBody) {
console.log(meBody);
}).catch(function(err) {
console.log(err);
});
Following a chain of links
It's possible to follow a chain of links with follow:
client.follow('rel1')
.then(function(resource1) {
return resource1.follow('rel2');
})
.then(function(resource2) {
return resource2.follow('rel3');
})
.then(function(resource3) {
console.log(resource3.getLinks());
});
As you can see, follow()
returns a Promise. However, the returned promise
has an additional follow()
function itself, which makes it possible to
shorten this to:
client
.follow('rel1')
.follow('rel2')
.follow('rel3')
.then(function(resource3) {
console.log(resource3.getLinks());
});
Providing custom options
restl uses request under the hood to do HTTP requests. Custom options
can be specified as such:
var bookMark = 'https://my-hal-api.example.org';
var options {
auth: {
user: 'foo',
pass: 'bar'
}
}
var restl = require('restl')(bookMark, options);
For a full list of possible options, check out the request documentation.
API
Client
Constructor
var client = new Client(bookMark, options);
bookMark
- The base URL of the web service.options
optional - A list of options for Request.
Client.getResource()
Returns a 'Resource' object based on the url. If
var resource = client.getResource(url);
url
- URL to fetch. Might be relative. If not provided, the bookMark is
fetched instead.
This function returns a Resource
.
Resource
Resource.get()
Returns the result of a GET
request. This function returns a Promise
.
resource.get().then(function(body) {
console.log(body);
});
If the resource was fetched earlier, it will return a cached copy.
Resource.put()
Updates the resource with a new representation
resource.put({ 'foo' : 'bar' });
This function returns a Promise that resolves to null
.
Resource.delete()
Deletes the resource.
resource.delete();
This function returns a Promise that resolves to null
.
Resource.post()
This function is meant to be an easy way to create new resources. It's not
necessarily for any type of POST
request, but it is really meant as a
convenience method APIs that follow the typical pattern of using POST
for
creation.
If the HTTP response from the server was successful and contained a Location
header, this method will resolve into a new Resource. For example, this might
create a new resource and then get a list of links after creation:
resource.post({ property: 'value'})
.then(function(newResource) {
return newResource.links();
})
.then(function(links) {
console.log(links);
});
Resource.refresh()
Refreshes the internal cache for a resource and does a GET
request again.
This function returns a Promise
that resolves when the operation is complete,
but the Promise
does not have a value.
resource.refresh().then(function() {
return resource.get()
}).then(function(body) {
});
Resource.links()
Returns a list of Link
objects for the resource.
resource.links().then(function(links) {
console.log(links);
});
You can also request only the links for a relation-type you are interested in:
resource.links('item').then(function(links) {
});
Resource.follow()
Follows a link, by it's relation-type and returns a new resource for the
target.
resource.follow('author').then(function(author) {
return author.get();
}).then(function(body) {
console.log(body);
});
The follow function returns a special kind of Promise that has a follow()
function itself.
This makes it possible to chain follows:
resource
.follow('author')
.follow('homepage')
.follow('icon');
Resource.followAll()
This method works like follow()
but resolves into a list of resources.
Multiple links with the same relation type can appear in resources; for
example in collections.
resource.followAll('item')
.then(function(items) {
console.log(items);
});
Resource.representation()
This function is similar to GET
, but instead of just returning a response
body, it returns a Representation
object.
Representation
The Representation is typically the 'body' of a resource in REST terminology.
It's the R in REST.
The Representation is what gets sent by a HTTP server in response to a GET
request, and it's what gets sent by a HTTP client in a POST
request.
The Representation provides access to the body, a list of links and HTTP
headers that represent real meta-data of the resource. Currently this is only
Content-Type
but this might be extended to include encoding, language and
cache-related information.
Representation.body
The body
property has the body contents of a PUT
request or a GET
response.
Representation.links
The links
property has the list of links for a resource.
Representation.contentType
The contentType
property has the value of the Content-Type
header for both
requests and responses.