Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

restl

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

restl - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

lib/followable-promise.js

15

changelog.md
ChangeLog
=========
0.0.3 (2017-02-06)
------------------
* Now using Bluebird for promises, so we can extend them.
* #2: Custom requests are now possible on `Resource` objects.
* #3: Promises returned from `follow()` now have a `follow()` function
themselves, making it extremely easy to hop from link to link.
* Added a `post()` method for making new resources. This function returns a
`Resource` object again if the response contained a `Location` header.
* #4: Things in the `_embedded` property are now also treated as links and can
be followed.
* The `links()` method on Resource now have a `rel` argument for easy filtering.
* Added a `followAll()` function for getting collections.
0.0.2 (2017-01-03)

@@ -5,0 +20,0 @@ ------------------

41

lib/representation.js
var Link = require('./link');
/**
* The Representation object is the Resource Representation. This might be
* response to a GET request.
*
* It typically includes the request body + a number of relevant http headers.
*/
var Representation = function(contentType, body) {

@@ -12,8 +18,14 @@

}
if (typeof this.body._embedded !== 'undefined') {
parseHALEmbedded(this);
}
}
/**
* Parse the HAL _links object and populate the 'links' property.
*/
var parseHALLinks = function(representation) {
for(relType in representation.body._links) {
for(var relType in representation.body._links) {
var links = representation.body._links[relType];

@@ -23,11 +35,11 @@ if (!Array.isArray(links)) {

}
for(link in links) {
for(var ii in links) {
representation.links.push(
new Link(
relType,
links[link].href,
links[link].type
links[ii].href,
links[ii].type
)
);
}
}
}

@@ -37,4 +49,23 @@

/**
* Parse the HAL _embedded object. Right now we're just grabbing the
* information from _embedded and turn it into links.
*/
var parseHALEmbedded = function(representation) {
for(var relType in representation.body._embedded) {
var embedded = representation.body._embedded[relType];
if (!Array.isArray(embedded)) {
embedded = [embedded];
}
for(var ii in embedded) {
representation.links.push(
new Link(
relType,
embedded[link]._links.self.href;
)
);
}
}
module.exports = Representation;

117

lib/resource.js

@@ -5,2 +5,3 @@ "use strict";

var url = require('url');
var FollowablePromise = require('./followable-promise');

@@ -34,3 +35,4 @@ var Resource = function(client, uri) {

return this.client.request.put({
return this.request({
method: 'PUT',
uri: this.uri,

@@ -49,3 +51,4 @@ body: body

return this.client.request.delete({
return this.request({
method: 'DELETE',
uri: this.uri,

@@ -60,2 +63,31 @@ body: body

/**
* Sends a POST request to the resource.
*
* This function assumes that POST is used to create new resources, and
* that the response will be a 201 Created along with a Location header that
* identifies the new resource location.
*
* This function returns a Promise that resolves into the newly created
* Resource.
*
* If no Location header was given, it will resolve still, but with an empty
* value.
*/
post: function(body) {
return this.request({
method: 'POST',
uri: this.uri,
body: body
}).then(function(response) {
if (response.headers.location) {
return new Resource(
this.client,
response.headers.uri
);
}
});
},
/**
* Refreshes the representation for this resource.

@@ -66,12 +98,12 @@ * Returns an empty Promise.

return this.client.request.get(this.uri)
.then(function(response) {
return this.request({
method: 'GET',
uri: this.uri
}).then(function(response) {
this.repr = new Representation(
response.headers['content-type'],
response.body
);
}.bind(this));
this.repr = new Representation(
response.headers['content-type'],
response.body
);
}.bind(this));
},

@@ -81,7 +113,11 @@

* Returns the links for this resource, as a promise.
*
* The rel argument is optional. If it's given, we will only return links
* from that relationship type.
*/
links: function() {
links: function(rel) {
return this.representation().then(function(r) {
return r.links;
if (!rel) return r.links;
return r.links.filter( function(item) { return item.rel === rel; } );
});

@@ -99,15 +135,19 @@

return this.links().then(function(links) {
return new FollowablePromise(function(res, rej) {
var link = links.find(function(link) {
return link.rel === rel;
});
if (!link) {
throw new Error('Relation with type ' + rel + ' not found on resource ' + this.uri);
}
return new Resource(
this.client,
url.resolve(this.uri, link.href)
);
this.links(rel)
.then(function(links) {
if (links.length === 0) {
throw new Error('Relation with type ' + rel + ' not found on resource ' + this.uri);
}
res(new Resource(
this.client,
url.resolve(this.uri, links[0].href)
));
}.bind(this))
.catch(function(reason) {
rej(reason);
});
}.bind(this));

@@ -118,2 +158,21 @@

/**
* Follows a relationship based on its reltype. This function returns a
* Promise that resolves to an array of Resource objects.
*
* If no resources were found, the array will be empty.
*/
followAll: function(rel) {
return this.links(rel).then(function(links) {
return links.map(function(link) {
return new Resource(
this.client,
url.resolve(this.uri, link.href)
);
});
});
},
/**
* Returns the representation for the object.

@@ -133,2 +192,12 @@ *

},
/**
* Does an arbitrary HTTP request on the resource, and returns the HTTP
* response object from the Request library, wrapped in a Promise.
*/
request: function(options) {
return this.client.request(options);
}

@@ -135,0 +204,0 @@

{
"name": "restl",
"version": "0.0.2",
"version": "0.0.3",
"description": "Generic hypermedia client.",

@@ -28,2 +28,3 @@ "main": "lib/index.js",

"dependencies": {
"bluebird": "^3.4.7",
"request": "^2.79.0",

@@ -30,0 +31,0 @@ "request-promise-any": "^1.0.3"

@@ -33,3 +33,3 @@ Restl - A hypermedia client for nodejs

* Resolve every URI to an absolute URI.
* Figuring out `_embedded`.
* Figuring caching resources from `_embedded`.
* Support HTTP `Link` header.

@@ -39,3 +39,5 @@ * Support non-JSON resources, including things like images.

* Parse [Atom][5].
* Built-in OAuth2.
### Post 1.0

@@ -46,2 +48,5 @@

* Support [`Prefer: return=representation`][6].
* Browser support (nodejs only at the moment, but only because of the Request
library.)
* Unittests

@@ -52,5 +57,8 @@ ### Already done:

* Basic HAL parsing.
* Normalizing `_links` and `_embedded`.
* `PUT` request.
* `DELETE` request.
* `POST` request
Usage

@@ -91,2 +99,33 @@ -----

### Following a chain of links
It's possible to follow a chain of links with follow:
```js
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:
```js
client
.follow('rel1')
.follow('rel2')
.follow('rel3')
.then(function(resource3) {
console.log(resource3.getLinks());
});
```
### Providing custom options

@@ -153,4 +192,46 @@

### `Resource.refresh()`
#### `Resource.put()`
Updates the resource with a new respresentation
```js
resource.put({ 'foo' : 'bar' });
```
This function returns a Promise that resolves to `null`.
#### `Resource.delete()`
Deletes the resource.
```js
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:
```js
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.

@@ -168,3 +249,3 @@ This function returns a `Promise` that resolves when the operation is complete,

### `Resource.links()`
#### `Resource.links()`

@@ -179,4 +260,13 @@ Returns a list of `Link` objects for the resource.

### `Resource.follow()`
You can also request only the links for a relation-type you are interested in:
```js
resource.links('item').then(function(links) {
});
```
#### `Resource.follow()`
Follows a link, by it's relation-type and returns a new resource for the

@@ -193,3 +283,60 @@ target.

The follow function returns a special kind of Promise that has a `follow()`
function itself.
This makes it possible to chain follows:
```js
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.
```js
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.
[1]: https://tools.ietf.org/html/rfc5988 "Web Linking"

@@ -196,0 +343,0 @@ [2]: http://stateless.co/hal_specification.html "HAL - Hypertext Application Language"

@@ -10,5 +10,34 @@ var restl = require('.');

var client = restl('http://192.168.0.26:3009', options);
var client = restl('http://192.168.0.26:3009/', options);
var home = client.getResource();
describe('creating a new location', () => async {
const accounts = await home
.follow('currentUser')
.follow('accounts')
.followAll('item');
const account = accounts[0];
const locations = await account.follow('locationCollection');
const newLocation = await locations.post({
title: 'Mac Donalds'
});
it('should return 201 Created');
it('should have created the new location', () => async {
const hal = await newLocation.get();
expect(hal).to.equal(...);
});
});
home.follow('currentUser')

@@ -15,0 +44,0 @@ .then(function(currentUser) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc