Skip to content

Commit 61d5c56

Browse files
committed
Merge pull request #23 from digitalsadhu/document_code
Cleanup and commenting code
2 parents a4272a7 + 4ca3a66 commit 61d5c56

File tree

9 files changed

+80
-41
lines changed

9 files changed

+80
-41
lines changed

lib/create.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
var url = require('url');
22

33
module.exports = function (app, options) {
4+
//get remote methods.
5+
//set strong-remoting for more information
6+
//https://github.com/strongloop/strong-remoting
47
var remotes = app.remotes();
58

9+
//register after remote method hook on all methods
610
remotes.after('**', function (ctx, next) {
11+
12+
//in this case we are only interested in handling create operations.
713
if (ctx.method.name === 'create') {
14+
15+
//JSON API specifies that created resources should have the
16+
//http status code of 201
817
ctx.res.statusCode = 201;
918

19+
//build the location url for the created resource.
1020
var location = url.format({
1121
protocol: ctx.req.protocol,
1222
host: ctx.req.get('host'),
1323
pathname: ctx.req.baseUrl + '/' + ctx.result.data.id
1424
});
1525

26+
//we don't need the links property so just delete it.
1627
delete ctx.result.links;
28+
29+
//JSON API specifies that when creating a resource, there should be a
30+
//location header set with the url of the created resource as the value
1731
ctx.res.append('Location', location);
1832
}
1933
next();

lib/deserialize.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,28 @@
33
module.exports = function (app) {
44
var remotes = app.remotes();
55

6+
//register a handler to run before all remote methods so that we can
7+
//transform JSON API structured JSON payload into something loopback
8+
//can work with.
69
remotes.before('**', function (ctx, next) {
10+
11+
//JSON api doesn't support PUT so we only need to apply our changes to
12+
//POST and PATCH operations.
713
if (ctx.req.method === 'POST' || ctx.req.method === 'PATCH') {
14+
15+
//set the JSON API Content-Type response header
816
ctx.res.set({'Content-Type': 'application/vnd.api+json'});
17+
18+
//check the incoming payload data to ensure it is valid according to the
19+
//JSON API spec.
920
var data = ctx.args.data;
1021
if (!data.data) return next(new Error('JSON API resource object must contain `data` property'));
1122
if (!data.data.type) return next(new Error('JSON API resource object must contain `data.type` property'));
12-
1323
if (ctx.req.method === 'PATCH') {
1424
if (!data.data.id) return next(new Error('JSON API resource object must contain `data.id` property'));
1525
}
1626

27+
//transform the payload
1728
ctx.args.data = data.data.attributes || {};
1829
}
1930

lib/headers.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ var bodyParser = require('body-parser');
55
module.exports = function (app, options) {
66

77
//registered at the beginning of the routes phase due to usage of
8-
//express app.use instead of app.middleware
8+
//express app.use instead of app.middleware.
9+
//We need to do this as bodyParser doesn't support
10+
//JSON APIs application/vnd.api+json format by default
911
app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
1012
};

lib/patch.js

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//copied in its entirity from loopbacks Model class.
2+
//it was necessary to do so as this function is used
3+
//in the other code below
14
function convertNullToNotFoundError (toModelName, ctx, cb) {
25
if (ctx.result !== null) return cb();
36

@@ -9,12 +12,30 @@ function convertNullToNotFoundError (toModelName, ctx, cb) {
912
cb(error);
1013
}
1114

12-
function fixHttpMethod (fn, name) {
13-
if (fn.http && fn.http.verb && fn.http.verb.toLowerCase() === 'put') fn.http.verb = 'patch';
14-
}
15-
1615
module.exports = function (app, options) {
16+
17+
//iterate over all loopback models. This gives us a constructor function
18+
//and allows us to overwrite the relationship methods:
19+
// - belongsToRemoting
20+
// - hasOneRemoting
21+
// - hasManyRemoting
22+
// - scopeRemoting
23+
// - etc
24+
//
25+
//Note: This does not seem ideal.
26+
//We are copying a tonne of code out of loopbacks Model class
27+
//and then modifying little bits of it below.
28+
// see: https://github.com/strongloop/loopback/blob/master/lib/model.js#L462-L661
29+
//Most likely this will be fragile and
30+
//require us to keep up to date with any chances introduced in loopback.
31+
//
32+
//It would be good to have a discussion with the strongloop guys and see
33+
//if there is a better way this can be done.
1734
app.models().forEach(function (ctor) {
35+
36+
//sets up remote relationship method belongsTo on any model that
37+
//has a belongsTo relationship defined in its .json file (or via the
38+
//node API)
1839
ctor.belongsToRemoting = function (relationName, relation, define) {
1940
var modelName = relation.modelTo && relation.modelTo.modelName;
2041
modelName = modelName || 'PersistedModel';
@@ -83,6 +104,10 @@ module.exports = function (app, options) {
83104
}, findHasManyRelationshipsFunc);
84105

85106
var createRelationshipFunc = function (cb) {
107+
//TODO: implement this
108+
//this is where we need to implement
109+
// POST /:model/:id/relationships/:relatedModel
110+
//
86111
// this['__get__' + pathName](cb);
87112
};
88113
define('__createRelationships__' + relationName, {
@@ -95,6 +120,10 @@ module.exports = function (app, options) {
95120
}, createRelationshipFunc);
96121

97122
var updateRelationshipsFunc = function (cb) {
123+
//TODO: implement this
124+
//this is where we need to implement
125+
// PATCH /:model/:id/relationships/:relatedModel
126+
//
98127
// this['__get__' + pathName](cb);
99128
};
100129
define('__updateRelationships__' + relationName, {
@@ -107,6 +136,10 @@ module.exports = function (app, options) {
107136
}, updateRelationshipsFunc);
108137

109138
var deleteRelationshipsFunc = function (cb) {
139+
//TODO: implement this
140+
//this is where we need to implement
141+
// DELETE /:model/:id/relationships/:relatedModel
142+
//
110143
// this['__get__' + pathName](cb);
111144
};
112145
define('__deleteRelationships__' + relationName, {
@@ -156,5 +189,12 @@ module.exports = function (app, options) {
156189
};
157190
});
158191

192+
//copied from loopbacks Model class.
193+
function fixHttpMethod (fn, name) {
194+
if (fn.http && fn.http.verb && fn.http.verb.toLowerCase() === 'put') fn.http.verb = 'patch';
195+
}
196+
197+
//iterate through all remote methods and swap PUTs to PATCHs
198+
//as PUT is not supported by JSON API.
159199
app.remotes().methods().forEach(fixHttpMethod);
160200
};

lib/removeRemoteMethods.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module.exports = function (app, options) {
22
var models = app.models;
33

4+
//use loopbacks standard API to disable all methods that JSON API
5+
//does not support.
46
var isStatic = true;
57
Object.keys(models).forEach(function (model) {
68
models[model].disableRemoteMethod('upsert', isStatic);

lib/serialize.js

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,6 @@ function pluralForModel (model) {
4444
return inflection.pluralize(model.sharedClass.name);
4545
}
4646

47-
//TODO: Not used!!
48-
// function modelNameForPlural (models, plural) {
49-
// return Object.keys(models).filter(function (name) {
50-
// if (models[name] && models[name].definition) {
51-
// return models[name].definition.settings.plural === plural;
52-
// }
53-
// return false;
54-
// })[0];
55-
// }
56-
57-
//TODO: Not used!!
58-
// function modelForPlural (models, plural) {
59-
// return models[modelNameForPlural(models, plural)];
60-
// }
61-
6247
function attributesForModel (model) {
6348
return Object.keys(model.definition.properties);
6449
}
@@ -75,15 +60,6 @@ function clone (object) {
7560
return JSON.parse(JSON.stringify(object));
7661
}
7762

78-
//TODO: Never used
79-
// function filterFromContext (context) {
80-
// try {
81-
// return JSON.parse(context.args.filter);
82-
// } catch (e) {
83-
// return false;
84-
// }
85-
// }
86-
8763
function modelNameFromContext (context) {
8864
return context.method.sharedClass.name;
8965
}
@@ -92,11 +68,6 @@ function urlFromContext (context) {
9268
return context.req.protocol + '://' + context.req.get('host') + context.req.originalUrl;
9369
}
9470

95-
//TODO: Never used!!
96-
// function primaryKeyFromModel(model) {
97-
// console.log(model.definition.properties)
98-
// }
99-
10071
function buildModelUrl (protocol, host, apiRoot, modelName, id) {
10172
var result;
10273
try {
@@ -165,8 +136,6 @@ module.exports = function (app, options) {
165136
dataLinks: {
166137
self: function (item) {
167138
if (relatedModelPlural) {
168-
//TODO: fix url building. Use url module.
169-
//currently doesnt take into account if /api/ is in the url etc.
170139
return buildModelUrl(ctx.req.protocol, ctx.req.get('host'), options.restApiRoot, relatedModelPlural, item.id);
171140
}
172141
return buildModelUrl(ctx.req.protocol, ctx.req.get('host'), options.restApiRoot, pluralForModel(app.models[modelName]), item.id);

lib/update.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module.exports = function (app, options) {
33

44
remotes.after('**', function (ctx, next) {
55
if (ctx.method.name === 'updateAttributes') {
6-
// ctx.res.statusCode = 201;
76

7+
//remote links object from resource response
88
delete ctx.result.links;
99
}
1010
next();

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "JSONAPI support for loopback",
55
"main": "lib/index.js",
66
"scripts": {
7-
"test": "mocha --reporter=spec ./test/**/*"
7+
"test": "npm run lint && mocha --reporter=spec ./test/**/*",
8+
"lint": "eslint ."
89
},
910
"repository": {
1011
"type": "git",

test/hasMany.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('loopback json api hasMany relationships', function () {
3030
JSONAPIComponent(app, {restApiRoot: '/'});
3131
});
3232

33-
describe('Post with no comments', function (done) {
33+
describe('Fetch a post with no comments', function (done) {
3434
beforeEach(function (done) {
3535
Post.create({
3636
title: 'my post without comments',
@@ -82,7 +82,7 @@ describe('loopback json api hasMany relationships', function () {
8282
});
8383
});
8484

85-
describe('Post with a comment', function (done) {
85+
describe('Fetch a post with a comment', function (done) {
8686
beforeEach(function (done) {
8787
Post.create({
8888
title: 'my post',

0 commit comments

Comments
 (0)