Skip to content
This repository has been archived by the owner on Nov 16, 2018. It is now read-only.

Fetch embedded resources #29

Merged
merged 4 commits into from
Aug 8, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@ waterwheel.populateResources()

`.getFieldData()` accepts no arguments. This returns the object from Waterwheel-Drupal that contains information about each field in the entity/bundle. For a list of fields, _to be used in `.setField()`_, something like `Object.keys(res.fields)` will work.

### Get Embedded Resources

```javascript
waterwheel.api.node.page.get(1, 'hal_json')
.then(res => waterwheel.fetchEmbedded(res))
.then(res => {
// res
})
.catch(err => {
// err
});
```
`.fetchEmbedded()` accepts 1 argument
- `entityJSON`: This should be a HAL+JSON structured object containing an `_embedded` key at the root.

When requesting embedded resources duplicates are removed to prevent extra HTTP requests. An array is returned with your original response and any embedded resources. If any of the subsequent requests fail, the promise is rejected.

### Entity Query

To take advantage of the Entity Query support, enable the [EntityQueryAPI](https://www.drupal.org/project/entityqueryapi) module. You do not need to run `.populateResources()` prior to using this functionality.
Expand Down
4 changes: 2 additions & 2 deletions lib/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module.exports = class Entity extends Request {
* The ID of name of the entity being requested.
* @param {object} body
* An object containing the request body to be sent.
* @param {string} [format=json]
* @param {string} [format=application/json]
* The format for the requested content.
* @returns {Promise} A Promise that when fulfilled returns a response containing the content entity in JSON (as of 8.2).
*/
Expand Down Expand Up @@ -71,7 +71,7 @@ module.exports = class Entity extends Request {

/**
* Get field data about the expected bundle
* @param {string} [format=application/json]
* @param {string} [format=json]
* The format of the content being posted.
* @return {promise}
* A promise resolved when the request for field data is complete,
Expand Down
26 changes: 26 additions & 0 deletions lib/waterwheel.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,30 @@ module.exports = class Waterwheel extends Request {
});
}

/**
* Fetch embedded resources from HAL+JSON documents
* @param {object} entityJSON
* An object, usually returned from Drupal, containing _embedded information
* @return {Promise}
* If no _embedded key is found, a rejection is returned, else a resolved
* promise with all the embedded resources requests completed.
*/
fetchEmbedded(entityJSON) {
if (!entityJSON || !entityJSON.hasOwnProperty('_embedded')) {
return Promise.reject('This is probably not HAL+JSON');
}

let links = [];

Object.keys(entityJSON._embedded).forEach(key => {
entityJSON._embedded[key].forEach(ref => {
links.push(ref._links.self.href.split(this.base)[1]);
});
});

links = Array.from(new Set(links));
Copy link

@infiniteluke infiniteluke Aug 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment about not wanting to fetch the same resource multiple times hence the use of Set could help future contributors. Also a note about Promise.all needing an array. ??


return Promise.all([Promise.resolve(entityJSON)].concat(links.map(link => this.issueRequest(methods.get, link))));
Copy link

@infiniteluke infiniteluke Aug 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming your doing this so that the parent entity response is provided adjacent to the embedded ones? A comment could help make the intent here clear.

}

};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "waterwheel",
"version": "0.7.0",
"version": "0.7.1",
"description": "A generic JavaScript helper library to query and manipulate Drupal 8 via core REST",
"author": "Preston So <preston.so@acquia.com>",
"contributors": [
Expand Down
30 changes: 30 additions & 0 deletions test/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,33 @@ test.cb('Populate Resources', t => {
t.end();
});
});

test('Fetch Embedded - Missing _embedded key', t => {
const waterwheel = new t.context.Waterwheel(t.context.base, t.context.credentials);
return waterwheel.fetchEmbedded({})
.catch(err =>{
t.is(err, 'This is probably not HAL+JSON');
});
});

test('Fetch Embedded - Missing response', t => {
const waterwheel = new t.context.Waterwheel(t.context.base, t.context.credentials);
return waterwheel.fetchEmbedded()
.catch(err =>{
t.is(err, 'This is probably not HAL+JSON');
});
});

test('Fetch Embedded', t => {
requireSubvert.subvert('axios', () => (
Promise.resolve({data: {halExample: 'Some HAL+JSON'}})
));

const waterwheel = new t.context.Waterwheel(t.context.base, t.context.credentials);
const halJSON = require('./sample/hal.example.json');
return waterwheel.fetchEmbedded(halJSON)
.then(res =>{
t.is(res.length, 4);
t.deepEqual(res[1], {halExample: 'Some HAL+JSON'});
});
});
141 changes: 141 additions & 0 deletions test/sample/hal.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"_links": {
"self": {
"href": "http://foo.dev/page/bruce-wayne?_format=hal_json"
},
"type": {
"href": "http://foo.dev/rest/type/node/page"
},
"http://foo.dev/rest/relation/node/page/uid": [{
"href": "http://foo.dev/user/1?_format=hal_json",
"lang": "en"
}],
"http://foo.dev/rest/relation/node/page/revision_uid": [{
"href": "http://foo.dev/user/1?_format=hal_json"
}],
"http://foo.dev/rest/relation/node/page/field_actor": [{
"href": "http://foo.dev/node/6?_format=hal_json"
}, {
"href": "http://foo.dev/node/8?_format=hal_json"
}]
},
"nid": [{
"value": "7"
}],
"uuid": [{
"value": "284365c0-fa63-43ac-ae68-d60600873c34"
}],
"vid": [{
"value": "7"
}],
"langcode": [{
"value": "en",
"lang": "en"
}],
"type": [{
"target_id": "page"
}],
"title": [{
"value": "Bruce Wayne",
"lang": "en"
}],
"_embedded": {
"http://foo.dev/rest/relation/node/page/uid": [{
"_links": {
"self": {
"href": "http://foo.dev/user/1?_format=hal_json"
},
"type": {
"href": "http://foo.dev/rest/type/user/user"
}
},
"uuid": [{
"value": "b578592a-a751-4993-9060-53f488597e59"
}],
"lang": "en"
}],
"http://foo.dev/rest/relation/node/page/revision_uid": [{
"_links": {
"self": {
"href": "http://foo.dev/user/1?_format=hal_json"
},
"type": {
"href": "http://foo.dev/rest/type/user/user"
}
},
"uuid": [{
"value": "b578592a-a751-4993-9060-53f488597e59"
}]
}],
"http://foo.dev/rest/relation/node/page/field_actor": [{
"_links": {
"self": {
"href": "http://foo.dev/node/6?_format=hal_json"
},
"type": {
"href": "http://foo.dev/rest/type/node/actor"
}
},
"uuid": [{
"value": "b5c619cd-1dfe-4c9d-afea-760a8eaf27c9"
}]
}, {
"_links": {
"self": {
"href": "http://foo.dev/node/8?_format=hal_json"
},
"type": {
"href": "http://foo.dev/rest/type/node/actor"
}
},
"uuid": [{
"value": "ac1ad040-c05c-45ac-82d7-5b3eda40e451"
}]
}]
},
"status": [{
"value": "1",
"lang": "en"
}],
"created": [{
"value": "1470156620",
"lang": "en"
}],
"changed": [{
"value": "1470170146",
"lang": "en"
}],
"promote": [{
"value": "0"
}],
"sticky": [{
"value": "0",
"lang": "en"
}],
"revision_timestamp": [{
"value": "1470156635"
}],
"revision_translation_affected": [{
"value": "1",
"lang": "en"
}],
"default_langcode": [{
"value": "1",
"lang": "en"
}],
"body": [{
"value": "some body",
"format": "basic_html",
"summary": "",
"lang": "en"
}],
"comment": [{
"status": "2",
"cid": "0",
"last_comment_timestamp": "1470156635",
"last_comment_name": null,
"last_comment_uid": "1",
"comment_count": "0",
"lang": "en"
}]
}