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

jsonapi-server

Package Overview
Dependencies
Maintainers
3
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsonapi-server - npm Package Compare versions

Comparing version 0.16.0 to 1.0.0

lib/pagination.js

9

CHANGELOG.md

@@ -53,1 +53,10 @@ 2015-06-29 - Initial release

2015-11-25 - v0.16.0
2015-12-03 - Top level jsonapi blocks
2015-12-05 - Tooling improvements
2015-12-07 - Efficient inclusions
2015-12-08 - Pagination support
2015-12-10 - CPU profiling
2015-12-10 - Move to lodash
2015-12-10 - Use filter[] instead of relationships[]
2015-12-10 - Inclusion bug fixes
2015-12-10 - v1.0.0

2

documentation/debugging.md

@@ -16,3 +16,5 @@

- jsonApi:include
- jsonApi:filter
- jsonApi:errors
- jsonApi:requestCounter

@@ -19,0 +21,0 @@

2

documentation/foreign-relations.md

@@ -177,3 +177,3 @@ ### Foreign Key Relations

// get full details of all linked resources (perform a search against the foreign key)
related: "http://localhost:16006/rest/articles/?relationships[comments]=6b017640-827c-4d50-8dcc-79d766abb408"
related: "http://localhost:16006/rest/articles/?filter[comments]=6b017640-827c-4d50-8dcc-79d766abb408"
}

@@ -180,0 +180,0 @@ }

@@ -60,1 +60,10 @@ ### Post Processing

http://localhost:16006/rest/articles?sort=+title
#### Pagination
Use `page[limit]=50` to limit the number of resources in a search request to 50.
Use `page[offset]=10` to chose which resulting resource should start the result set.
To fetch resources 100-149:
http://localhost:16006/rest/articles?page[offset]=100&page[limit]=50

@@ -76,3 +76,3 @@ var jsonApi = require("../../.");

tags: [
{ type: "tags", id: "7541a4de-4986-4597-81b9-cf31b6762486" }
{ type: "tags", id: "8d196606-134c-4504-a93a-0d372f78d6c5" }
],

@@ -79,0 +79,0 @@ photos: [

@@ -16,2 +16,7 @@ var jsonApi = require("../../.");

as: "tags"
}),
parent: jsonApi.Joi.one("tags"),
children: jsonApi.Joi.belongsToMany({
resource: "tags",
as: "parent"
})

@@ -23,3 +28,4 @@ },

type: "tags",
name: "live"
name: "live",
parent: { type: "tags", id: "2a3bdea4-a889-480d-b886-104498c86f69" }
},

@@ -29,3 +35,4 @@ {

type: "tags",
name: "staging"
name: "staging",
parent: { type: "tags", id: "6ec62f6d-9f82-40c5-b4f4-279ed1765492" }
},

@@ -35,5 +42,18 @@ {

type: "tags",
name: "needs-work"
name: "building",
parent: { type: "tags", id: "68538177-7a62-4752-bc4e-8f971d253b42" }
},
{
id: "68538177-7a62-4752-bc4e-8f971d253b42",
type: "tags",
name: "development",
parent: { type: "tags", id: "8d196606-134c-4504-a93a-0d372f78d6c5" }
},
{
id: "8d196606-134c-4504-a93a-0d372f78d6c5",
type: "tags",
name: "planning",
parent: null
}
]
});

@@ -11,5 +11,7 @@ "use strict";

include: require("debug")("jsonApi:include"),
filter: require("debug")("jsonApi:filter"),
validationInput: require("debug")("jsonApi:validation:input"),
validationOutput: require("debug")("jsonApi:validation:output"),
errors: require("debug")("jsonApi:errors")
errors: require("debug")("jsonApi:errors"),
requestCounter: require("debug")("jsonApi:requestCounter")
};

@@ -14,50 +14,39 @@ "use strict";

handlerEnforcer._search = function(handlers) {
var original = handlers.search;
return function(request, callback) {
original.call(handlers, request, function(err, resources) {
debug.handler.search(JSON.stringify(request.params), JSON.stringify(err), JSON.stringify(resources));
return callback(err, resources);
handlerEnforcer._wrapHandler = function(handlers, operation, outCount) {
var original = handlers[operation];
return function() {
var argsIn = Array.prototype.slice.call(arguments);
var requestParams = argsIn[0].params;
var callback = argsIn.pop();
argsIn.push(function() {
var argsOut = Array.prototype.slice.call(arguments);
argsOut = argsOut.slice(0, outCount);
while (argsOut.length < outCount) {
argsOut.push(null);
}
debug.handler[operation](JSON.stringify(requestParams), JSON.stringify(argsOut));
return callback.apply(null, argsOut);
});
original.apply(handlers, argsIn);
};
};
handlerEnforcer._search = function(handlers) {
return handlerEnforcer._wrapHandler(handlers, "search", 3);
};
handlerEnforcer._find = function(handlers) {
var original = handlers.find;
return function(request, callback) {
original.call(handlers, request, function(err, resource) {
debug.handler.find(JSON.stringify(request.params), JSON.stringify(err), JSON.stringify(resource));
return callback(err, resource);
});
};
return handlerEnforcer._wrapHandler(handlers, "find", 2);
};
handlerEnforcer._create = function(handlers) {
var original = handlers.create;
return function(request, newResource, callback) {
original.call(handlers, request, newResource, function(err, handledResource) {
debug.handler.create(JSON.stringify(request.params), JSON.stringify(newResource), JSON.stringify(err), JSON.stringify(handledResource));
return callback(err, handledResource);
});
};
return handlerEnforcer._wrapHandler(handlers, "create", 2);
};
handlerEnforcer._update = function(handlers) {
var original = handlers.update;
return function(request, partialResource, callback) {
original.call(handlers, request, partialResource, function(err, modifiedResource) {
debug.handler.update(JSON.stringify(request.params), JSON.stringify(partialResource), JSON.stringify(err), JSON.stringify(modifiedResource));
return callback(err, modifiedResource);
});
};
return handlerEnforcer._wrapHandler(handlers, "update", 2);
};
handlerEnforcer._delete = function(handlers) {
var original = handlers.delete;
return function(request, callback) {
original.call(handlers, request, function(err) {
debug.handler.delete(JSON.stringify(request.params), JSON.stringify(err));
return callback(err);
});
};
return handlerEnforcer._wrapHandler(handlers, "delete", 1);
};

@@ -6,3 +6,6 @@ "use strict";

var _ = require("underscore");
var _ = {
assign: require("lodash.assign"),
pick: require("lodash.pick")
};
var ourJoi = require("./ourJoi.js");

@@ -12,2 +15,3 @@ var router = require("./router.js");

var handlerEnforcer = require("./handlerEnforcer.js");
var pagination = require("./pagination.js");
var routes = require("./routes");

@@ -68,3 +72,3 @@ var url = require("url");

resourceConfig.searchParams = _.extend({
resourceConfig.searchParams = _.assign({
type: ourJoi.Joi.any().required().valid(resourceConfig.resource)

@@ -84,9 +88,6 @@ .description("Always \"" + resourceConfig.resource + "\"")

.description("An attribute to include")
.example("title"),
relationships: ourJoi.Joi.any()
.description("An attribute to include")
.example("title")
}, resourceConfig.searchParams);
}, resourceConfig.searchParams, pagination.joiPageDefinition);
resourceConfig.attributes = _.extend({
resourceConfig.attributes = _.assign({
id: ourJoi.Joi.string().required()

@@ -93,0 +94,0 @@ .description("Unique resource identifier")

"use strict";
var _ = require("underscore");
var _ = {
assign: require("lodash.assign")
};

@@ -25,25 +27,14 @@ var MemoryStore = module.exports = function MemoryStore() {

/**
Search for a list of resources, give a resource type.
Search for a list of resources, given a resource type.
*/
MemoryStore.prototype.search = function(request, callback) {
// If a relationships param is passed in, filter against those relations
if (request.params.relationships) {
var mustMatch = request.params.relationships;
var matches = resources[request.params.type].filter(function(anyResource) {
var match = true;
Object.keys(mustMatch).forEach(function(i) {
var fKeys = anyResource[i];
if (!(fKeys instanceof Array)) fKeys = [ fKeys ];
fKeys = fKeys.map(function(j) { return j.id; });
if (fKeys.indexOf(mustMatch[i]) === -1) {
match = false;
}
});
return match;
});
return callback(null, matches);
var self = this;
var results = [].concat(resources[request.params.type]);
self._sortList(request, results);
var resultCount = results.length;
if (request.params.page) {
results = results.slice(request.params.page.offset, request.params.page.offset + request.params.page.limit);
}
// No specific search params are supported, so return ALL resources of the requested type
return callback(null, resources[request.params.type]);
return callback(null, results, resultCount);
};

@@ -111,3 +102,3 @@

// Merge the partialResource over the original
theResource = _.extend(theResource, partialResource);
theResource = _.assign(theResource, partialResource);

@@ -121,1 +112,26 @@ // Push the newly updated resource back into the in-memory store

};
/**
Internal helper function to sort data
*/
MemoryStore.prototype._sortList = function(request, list) {
var attribute = request.params.sort;
if (!attribute) return;
var ascending = 1;
attribute = ("" + attribute);
if (attribute[0] === "-") {
ascending = -1;
attribute = attribute.substring(1, attribute.length);
}
list.sort(function(a, b) {
if (typeof a[attribute] === "string") {
return a[attribute].localeCompare(b[attribute]) * ascending;
} else if (typeof a[attribute] === "number") {
return (a[attribute] - b[attribute]) * ascending;
} else {
return 0;
}
});
};

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

var jsonApi = require("..");
var _ = require("underscore");
var debug = require("./debugging.js");
var externalRequest = require("request").defaults({

@@ -41,6 +41,18 @@ pool: { maxSockets: Infinity }

var resourcesToFetch = dataItems.map(function(dataItem) {
return jsonApi._apiConfig.pathPrefix + dataItem.type + "/" + dataItem.id;
var resourcesToFetch = dataItems.reduce(function(map, dataItem) {
map[dataItem.type] = map[dataItem.type] || [ ];
map[dataItem.type].push(dataItem.id);
return map;
}, { });
resourcesToFetch = Object.keys(resourcesToFetch).map(function(type) {
var ids = resourcesToFetch[type];
var urlJoiner = "&filter[id]=";
ids = urlJoiner + ids.join(urlJoiner);
return jsonApi._apiConfig.pathPrefix + type + "/?" + ids;
});
async.map(resourcesToFetch, function(related, done) {
debug.include(related);
externalRequest({

@@ -79,12 +91,10 @@ method: "GET",

items.forEach(function(item) {
Object.keys(schema).map(function(i) {
return _.extend({ name: i }, schema[i]);
}).filter(function(schemaProperty) {
var settings = schemaProperty._settings;
return settings && settings.__as;
}).forEach(function(schemaProperty) {
item[schemaProperty.name] = undefined;
});
for (var i in schema) {
var settings = schema[i]._settings;
if (settings && settings.__as) {
item[i] = undefined;
}
}
});
return callback();
};
"use strict";
var filter = module.exports = { };
var _ = {
assign: require("lodash.assign")
};
var debug = require("../debugging.js");
filter.action = function(request, response, callback) {
var allFilters = request.params.filter;
var allFilters = _.assign({ }, request.params.filter);
if (!allFilters) return callback();

@@ -29,2 +34,3 @@

if (!filter._filterKeepObject(response.data[j], filters)) {
debug.filter("removed", filters, JSON.stringify(response.data[j].attributes));
response.data.splice(j, 1);

@@ -36,2 +42,3 @@ j--;

if (!filter._filterKeepObject(response.data, filters)) {
debug.filter("removed", filters, JSON.stringify(response.data.attributes));
response.data = null;

@@ -61,13 +68,48 @@ }

filter._filterKeepObject = function(someObject, filters) {
for (var k in filters) {
var whitelist = filters[k].split(",");
var propertyText = (someObject.attributes[k] || "");
var matchOR = false;
for (var j = 0; j < whitelist.length; j++) {
var textToMatch = whitelist[j];
if (filter._filterMatches(textToMatch, propertyText)) matchOR = true;
for (var filterName in filters) {
var whitelist = filters[filterName].split(",");
if (someObject.attributes.hasOwnProperty(filterName) || (filterName === "id")) {
var attributeValue = someObject.attributes[filterName] || "";
if (filterName === "id") attributeValue = someObject.id;
var attributeMatches = filter._attributesMatchesOR(attributeValue, whitelist);
if (!attributeMatches) return false;
}
if (!matchOR) return false;
if (someObject.relationships.hasOwnProperty(filterName)) {
var relationships = someObject.relationships[filterName] || "";
var relationshipMatches = filter._relationshipMatchesOR(relationships, whitelist);
if (!relationshipMatches) return false;
}
}
return true;
};
filter._attributesMatchesOR = function(attributeValue, whitelist) {
var matchOR = false;
whitelist.forEach(function(textToMatch) {
if (filter._filterMatches(textToMatch, attributeValue)) {
matchOR = true;
}
});
return matchOR;
};
filter._relationshipMatchesOR = function(relationships, whitelist) {
var matchOR = false;
var data = relationships.data;
if (!data) return false;
if (!(data instanceof Array)) data = [ data ];
data = data.map(function(relation) {
return relation.id;
});
whitelist.forEach(function(textToMatch) {
if (data.indexOf(textToMatch) !== -1) {
matchOR = true;
}
});
return matchOR;
};

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

var jsonApi = require("../jsonApi.js");
var _ = require("underscore");
var _ = {
unique: require("lodash.uniq")
};
var externalRequest = require("request").defaults({

@@ -31,3 +33,3 @@ pool: { maxSockets: Infinity }

response.included = includePP._getDataItemsFromTree(includeTree);
response.included = _.uniq(response.included, false, function(someItem) {
response.included = _.unique(response.included, false, function(someItem) {
return someItem.type + "~~" + someItem.id;

@@ -73,2 +75,8 @@ });

filter = filter[first] || { };
if (filter instanceof Array) {
filter = filter.filter(function(i) {
return i instanceof Object;
}).pop();
}
if (!node[first]) {

@@ -81,5 +89,7 @@ node[first] = {

for (var i in filter) {
if (!(typeof filter[i] === "string" || (filter[i] instanceof Array))) continue;
node[first]._filter.push("filter[" + i + "]=" + filter[i]);
if (!((filter instanceof Array) && (filter.length === 0))) {
for (var i in filter) {
if (!(typeof filter[i] === "string" || (filter[i] instanceof Array))) continue;
node[first]._filter.push("filter[" + i + "]=" + filter[i]);
}
}

@@ -118,31 +128,72 @@ }

var resourcesToFetch = includeTree._dataItems.map(function(dataItem) {
var map = {
primary: { },
foreign: { }
};
includeTree._dataItems.forEach(function(dataItem) {
if (!dataItem) return [ ];
return Object.keys(dataItem.relationships || { }).filter(function(keyName) {
return (keyName[0] !== "_") && (includes.indexOf(keyName) !== -1);
}).map(function(keyName) {
var url = dataItem.relationships[keyName].links.related;
if (url.indexOf("?") === -1) url += "?";
if (includeTree[keyName]._filter) {
url += "&" + includeTree[keyName]._filter.join("&");
}).forEach(function(relation) {
var someRelation = dataItem.relationships[relation];
if (someRelation.meta.relation === "primary") {
var relationItems = someRelation.data;
if (!relationItems) return;
if (!(relationItems instanceof Array)) relationItems = [ relationItems ];
relationItems.forEach(function(relationItem) {
var key = relationItem.type + "~~" + relation + "~~" + relation;
map.primary[key] = map.primary[key] || [ ];
map.primary[key].push(relationItem.id);
});
}
return keyName + "~~" + url;
if (someRelation.meta.relation === "foreign") {
var key = someRelation.meta.as + "~~" + someRelation.meta.belongsTo + "~~" + relation;
map.foreign[key] = map.foreign[key] || [ ];
map.foreign[key].push(dataItem.id);
}
});
});
resourcesToFetch = [].concat.apply([], resourcesToFetch);
resourcesToFetch = _.unique(resourcesToFetch);
var resourcesToFetch = [];
Object.keys(map.primary).forEach(function(relation) {
var ids = _.unique(map.primary[relation]);
var parts = relation.split("~~");
var urlJoiner = "&filter[id]=";
ids = urlJoiner + ids.join(urlJoiner);
if (includeTree[parts[1]]._filter) {
ids += "&" + includeTree[parts[1]]._filter.join("&");
}
resourcesToFetch.push({
url: jsonApi._apiConfig.pathPrefix + parts[0] + "/?" + ids,
as: relation
});
});
Object.keys(map.foreign).forEach(function(relation) {
var ids = _.unique(map.foreign[relation]);
var parts = relation.split("~~");
var urlJoiner = "&filter[" + parts[0] + "]=";
ids = urlJoiner + ids.join(urlJoiner);
if (includeTree[parts[2]]._filter) {
ids += "&" + includeTree[parts[2]]._filter.join("&");
}
resourcesToFetch.push({
url: jsonApi._apiConfig.pathPrefix + parts[1] + "/?" + ids,
as: relation
});
});
async.map(resourcesToFetch, function(related, done) {
var parts = related.split("~~");
var type = parts[0];
var link = parts[1];
var parts = related.as.split("~~");
debug.include(related);
debug.include(link);
externalRequest({
method: "GET",
uri: link,
uri: related.url,
headers: request.safeHeaders
}, function(err, res, json) {
// console.log(err, json)
if (err || !json) {

@@ -167,3 +218,3 @@ return done(null);

if (!(data instanceof Array)) data = [ data ];
includeTree[type]._dataItems = includeTree[type]._dataItems.concat(data);
includeTree[parts[2]]._dataItems = includeTree[parts[2]]._dataItems.concat(data);
return done();

@@ -170,0 +221,0 @@ });

"use strict";
var responseHelper = module.exports = { };
var _ = require("underscore");
var _ = {
assign: require("lodash.assign"),
pick: require("lodash.pick")
};
var async = require("async");
var pagination = require("./pagination.js");
var Joi = require("joi");

@@ -139,4 +143,4 @@ var debug = require("./debugging.js");

// get full details of all linked resources
// /rest/bookings/?relationships[customer]=26aa8a92-2845-4e40-999f-1fa006ec8c63
link.links.related = responseHelper._baseUrl + relatedResource + "/?relationships[" + schemaProperty._settings.__as + "]=" + item.id;
// /rest/bookings/?filter[customer]=26aa8a92-2845-4e40-999f-1fa006ec8c63
link.links.related = responseHelper._baseUrl + relatedResource + "/?filter[" + schemaProperty._settings.__as + "]=" + item.id;
if (!item[linkProperty]) {

@@ -158,6 +162,9 @@ link.data = undefined;

responseHelper.generateError = function(request, err) {
debug.errors(err);
debug.errors(request.route.verb, request.route.combined, JSON.stringify(err));
if (!(err instanceof Array)) err = [ err ];
var errorResponse = {
jsonapi: {
version: "1.0"
},
meta: responseHelper._generateMeta(request),

@@ -180,8 +187,11 @@ links: {

responseHelper._generateResponse = function(request, resourceConfig, sanitisedData) {
responseHelper._generateResponse = function(request, resourceConfig, sanitisedData, handlerTotal) {
return {
meta: responseHelper._generateMeta(request),
links: {
jsonapi: {
version: "1.0"
},
meta: responseHelper._generateMeta(request, handlerTotal),
links: _.assign({
self: responseHelper._baseUrl + request.route.path + (request.route.query ? ("?" + request.route.query) : "")
},
}, pagination.generatePageLinks(request, handlerTotal)),
data: sanitisedData

@@ -191,4 +201,10 @@ };

responseHelper._generateMeta = function() {
return responseHelper._metadata;
responseHelper._generateMeta = function(request, handlerTotal) {
var meta = _.assign({ }, responseHelper._metadata);
if (handlerTotal) {
meta.page = pagination.generateMetaSummary(request, handlerTotal);
}
return meta;
};
"use strict";
var router = module.exports = { };
var _ = require("underscore");
var _ = {
assign: require("lodash.assign"),
omit: require("lodash.omit")
};
var express = require("express");

@@ -11,2 +14,3 @@ var app = express();

var jsonApi = require("./jsonApi.js");
var debug = require("./debugging.js");
var url = require("url");

@@ -52,9 +56,8 @@

// var requestId = 0;
// app.route("*").all(function(req, res, next) {
// req.query.requestId = requestId;
// console.log(requestId, "===", req.url);
// requestId++;
// next();
// });
var requestId = 0;
app.route("*").all(function(req, res, next) {
debug.requestCounter(requestId++, req.url);
if (requestId > 1000) requestId = 0;
next();
});

@@ -124,3 +127,3 @@ router.listen = function(port) {

return {
params: _.extend(req.params, req.body, req.query),
params: _.assign(req.params, req.body, req.query),
headers: req.headers,

@@ -130,2 +133,3 @@ safeHeaders: _.omit(req.headers, headersToRemove),

route: {
verb: req.method,
host: req.headers.host,

@@ -137,5 +141,5 @@ base: jsonApi._apiConfig.base,

protocol: jsonApi._apiConfig.protocol,
hostname: req.headers.host,
pathname: req.url
})
hostname: jsonApi._apiConfig.hostname,
port: jsonApi._apiConfig.port
}) + req.url
}

@@ -142,0 +146,0 @@ };

@@ -56,3 +56,3 @@ "use strict";

},
function(results, callback) {
function(results, pageData, callback) {
searchResults = results.map(function(result) {

@@ -59,0 +59,0 @@ return {

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

var async = require("async");
var _ = require("underscore");
var _ = {
assign: require("lodash.assign")
};
var uuid = require("node-uuid");

@@ -35,3 +37,3 @@ var helper = require("./helper.js");

var theirs = request.params.data;
theirResource = _.extend({
theirResource = _.assign({
id: uuid.v4(),

@@ -38,0 +40,0 @@ type: request.params.type

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

var router = require("../router.js");
var pagination = require("../pagination.js");
var postProcess = require("../postProcess.js");

@@ -19,2 +20,3 @@ var responseHelper = require("../responseHelper.js");

var response;
var paginationInfo;

@@ -28,34 +30,7 @@ async.waterfall([

},
function(callback) {
if (!request.params.relationships) return callback();
var target = Object.keys(request.params.relationships)[0];
var relation = resourceConfig.attributes[target];
if (!relation || !relation._settings || !(relation._settings.__one || relation._settings.__many)) {
return callback({
status: "403",
code: "EFORBIDDEN",
title: "Request validation failed",
detail: "Requested relation \"" + target + "\" does not exist on " + request.params.type
});
}
if (relation._settings.__as) {
return callback({
status: "403",
code: "EFORBIDDEN",
title: "Request validation failed",
detail: "Requested relation \"" + target + "\" is a foreign reference and does not exist on " + request.params.type
});
}
return callback();
},
function validateFilterParams(callback) {
var allFilters = request.params.filter;
if (!allFilters) return callback();
if (!request.params.filter) return callback();
var filters = { };
for (var i in allFilters) {
for (var i in request.params.filter) {
if (request.params.filter[i] instanceof Object) continue;
if (!request.resourceConfig.attributes[i]) {

@@ -69,16 +44,28 @@ return callback({

}
if (allFilters[i] instanceof Array) {
allFilters[i] = allFilters[i].join(",");
var relationSettings = request.resourceConfig.attributes[i]._settings;
if (relationSettings && relationSettings.__as) {
return callback({
status: "403",
code: "EFORBIDDEN",
title: "Request validation failed",
detail: "Requested relation \"" + i + "\" is a foreign reference and does not exist on " + request.params.type
});
}
filters[i] = allFilters[i];
}
request.params.filter = filters;
return callback();
},
function validatePaginationParams(callback) {
pagination.validatePaginationParams(request);
return callback();
},
function(callback) {
resourceConfig.handlers.search(request, callback);
},
function(results, callback) {
searchResults = results;
function enforcePagination(results, pageInfo, callback) {
searchResults = pagination.enforcePagination(request, results);
paginationInfo = pageInfo;
return callback();
},
function(callback) {
postProcess.fetchForeignKeys(request, searchResults, resourceConfig.attributes, callback);

@@ -90,3 +77,3 @@ },

function(sanitisedData, callback) {
response = responseHelper._generateResponse(request, resourceConfig, sanitisedData);
response = responseHelper._generateResponse(request, resourceConfig, sanitisedData, paginationInfo);
response.included = [ ];

@@ -93,0 +80,0 @@ postProcess.handle(request, response, callback);

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

var async = require("async");
var _ = require("underscore");
var _ = {
assign: require("lodash.assign"),
pick: require("lodash.pick")
};
var helper = require("./helper.js");

@@ -34,3 +37,3 @@ var router = require("../router.js");

var theirs = request.params.data;
theirResource = _.extend({
theirResource = _.assign({
id: request.params.id,

@@ -37,0 +40,0 @@ type: request.params.type

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

var async = require("async");
var _ = require("underscore");
var _ = {
assign: require("lodash.assign")
};
var helper = require("./helper.js");

@@ -34,3 +36,3 @@ var router = require("../router.js");

var theirs = request.params.data;
theirResource = _.extend({
theirResource = _.assign({
id: request.params.id,

@@ -37,0 +39,0 @@ type: request.params.type

@@ -69,2 +69,9 @@ "use strict";

type: "string"
},
page: {
name: "page",
in: "query",
description: "Pagination namespace",
required: false,
type: "string"
}

@@ -71,0 +78,0 @@ },

@@ -119,4 +119,13 @@ "use strict";

type: "object",
required: [ "meta, links" ],
required: [ "jsonapi", "meta, links" ],
properties: {
jsonapi: {
type: "object",
required: [ "version" ],
properties: {
version: {
type: "string"
}
}
},
meta: {

@@ -131,2 +140,14 @@ type: "object"

type: "string"
},
first: {
type: "string"
},
last: {
type: "string"
},
next: {
type: "string"
},
prev: {
type: "string"
}

@@ -133,0 +154,0 @@ }

@@ -142,3 +142,13 @@ "use strict";

type: "object",
required: [ "jsonapi", "meta", "links", "errors" ],
properties: {
jsonapi: {
type: "object",
required: [ "version" ],
properties: {
version: {
type: "string"
}
}
},
meta: {

@@ -145,0 +155,0 @@ type: "object"

{
"name": "jsonapi-server",
"version": "0.16.0",
"version": "1.0.0",
"description": "A fully featured NodeJS sever implementation of json:api. You provide the resources, we provide the api.",

@@ -28,5 +28,8 @@ "keywords": [

"joi": "6.7.1",
"lodash.assign": "3.2.0",
"lodash.omit": "3.1.0",
"lodash.pick": "3.1.0",
"lodash.uniq": "3.2.2",
"node-uuid": "1.4.3",
"request": "2.63.0",
"underscore": "1.8.3"
"request": "2.63.0"
},

@@ -40,12 +43,14 @@ "devDependencies": {

"plato": "1.5.0",
"mocha-performance": "0.1.0"
"mocha-performance": "0.1.0",
"v8-profiler": "5.5.0",
"node-inspector": "0.12.5"
},
"scripts": {
"test": "./node_modules/mocha/bin/mocha -R spec ./test/*.js",
"test": "node ./node_modules/mocha/bin/mocha -R spec ./test/*.js",
"start": "node example/server.js",
"coveralls": "./node_modules/mocha/bin/mocha --require blanket --reporter mocha-lcov-reporter ./test/*.js | ./node_modules/coveralls/bin/coveralls.js",
"coverage": "./node_modules/mocha/bin/mocha --require blanket --reporter html-cov ./test/*.js > coverage.html",
"complexity": "./node_modules/plato/bin/plato -r -d complexity lib",
"coveralls": "node ./node_modules/mocha/bin/mocha --require blanket --reporter mocha-lcov-reporter ./test/*.js | node ./node_modules/coveralls/bin/coveralls.js",
"coverage": "node ./node_modules/mocha/bin/mocha --require blanket --reporter html-cov ./test/*.js > coverage.html",
"complexity": "node ./node_modules/plato/bin/plato -r -d complexity lib",
"performance": "node --allow-natives-syntax --harmony ./node_modules/mocha/bin/_mocha --reporter mocha-performance ./test/*.js",
"lint": "./node_modules/.bin/eslint ./example/*.js ./lib/* ./test/*.js --quiet && echo '✔ All good!'"
"lint": "node ./node_modules/eslint/bin/eslint ./example ./lib ./test --quiet && echo '✔ All good!'"
},

@@ -52,0 +57,0 @@ "config": {

@@ -5,2 +5,3 @@ [![Coverage Status](https://coveralls.io/repos/holidayextras/jsonapi-server/badge.svg?branch=master)](https://coveralls.io/r/holidayextras/jsonapi-server?branch=master)

[![Code Climate](https://codeclimate.com/github/holidayextras/jsonapi-server/badges/gpa.svg)](https://codeclimate.com/github/holidayextras/jsonapi-server)
[![Codacy Badge](https://api.codacy.com/project/badge/grade/dd604d6548d8467caa224f078d59b182)](https://www.codacy.com/app/oliver-rumbelow/jsonapi-server)
[![Dependencies Status](https://david-dm.org/holidayextras/jsonapi-server.svg)](https://david-dm.org/holidayextras/jsonapi-server)

@@ -7,0 +8,0 @@

@@ -7,3 +7,19 @@ "use strict";

var swaggerValidator = require("./swaggerValidator.js");
var profiler = require("v8-profiler");
var fs = require("fs");
var path = require("path");
before(function() {
profiler.startProfiling("", true);
});
after(function(done) {
var profile = profiler.stopProfiling("");
var profileFileName = "jsonapi-server.cpuprofile";
var filePath = path.join(__dirname, "..", profileFileName);
fs.writeFileSync(filePath, JSON.stringify(profile));
console.error("Saved CPU profile to", filePath);
done();
});
testHelpers.validateError = function(json) {

@@ -17,3 +33,3 @@ try {

var keys = Object.keys(json);
assert.deepEqual(keys, [ "meta", "links", "errors" ], "Errors should have specific properties");
assert.deepEqual(keys, [ "jsonapi", "meta", "links", "errors" ], "Errors should have specific properties");
assert.equal(typeof json.links.self, "string", "Errors should have a \"self\" link");

@@ -40,4 +56,6 @@ assert.ok(json.errors instanceof Array, "errors should be an array");

assert.ok(json instanceof Object, "Response should be an object");
assert.ok(json.jsonapi instanceof Object, "Response should have a jsonapi block");
assert.ok(json.meta instanceof Object, "Response should have a meta block");
assert.ok(json.links instanceof Object, "Response should have a links block");
assert.ok(!(json.errors instanceof Object), "Response should not have any errors");
assert.equal(typeof json.links.self, "string", "Response should have a \"self\" link");

@@ -48,5 +66,2 @@ return json;

testHelpers.validateRelationship = function(relationship) {
var keys = Object.keys(relationship);
assert.deepEqual(keys, [ "meta", "links", "data" ], "Relationships should have specific properties");
assert.ok(relationship.meta instanceof Object, "Relationships should have a meta block");

@@ -53,0 +68,0 @@ assert.equal(typeof relationship.meta.relation, "string", "Relationships should have a relation type");

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