From 6d8942e53d8312ceacf36cb466ea28ac252ae7cc Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 19:53:38 +0200 Subject: [PATCH 01/11] Expect Bad request (400) to be sent if input is not a valid JSON API --- .../integration/controllers/Errors.test.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/dummy/test/integration/controllers/Errors.test.js b/tests/dummy/test/integration/controllers/Errors.test.js index 9e06586..89409ad 100644 --- a/tests/dummy/test/integration/controllers/Errors.test.js +++ b/tests/dummy/test/integration/controllers/Errors.test.js @@ -166,3 +166,35 @@ describe('Error handling', function() { }); }); }); + +describe('Submit invalid data', function() { + describe('POST invalid /users ', function() { + it('Should return 400', function (done) { + + request(sails.hooks.http.app) + .post('/users') + .send({ + data: { + foo: { + + } + } + }) + .expect(400) + .expect(validateJSONapi) + .expect({ + 'errors': [ + { + status: "400", + title: 'Bad request', + detail: 'Invalid JSON API data', + links: { + self: 'http://jsonapi.org/format/' + } + } + ] + }) + .end(done) + }); + }); +}); From 5cba67c0ce28d4e8bc1d10e73e327d0b1c105b31 Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 19:29:46 +0200 Subject: [PATCH 02/11] Update jsonapi-validation to have proper required fields for resources See https://github.com/elliotttf/jsonapi-validator/issues/29 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6ce67c1..90460d5 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "dependencies": { "clean-object": "^1.0.2", "json-api-serializer": "1.0.0", + "jsonapi-validator": "https://github.com/dynamiccast/jsonapi-validator.git#id-should-not-be-required-in-resource", "lodash": "3.10.1", "path": "^0.12.7", "pluralize": "^2.0.0", From d4772b248a89ab6a40d7dcd0a2851c1872f64d53 Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Mon, 11 Jul 2016 12:18:53 +0200 Subject: [PATCH 03/11] Add jsonapi-validator to validate input JSON data --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 90460d5..dbcdf4d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "clean-object": "^1.0.2", "json-api-serializer": "1.0.0", - "jsonapi-validator": "https://github.com/dynamiccast/jsonapi-validator.git#id-should-not-be-required-in-resource", + "jsonapi-validator": "^2.0.0", "lodash": "3.10.1", "path": "^0.12.7", "pluralize": "^2.0.0", From f840f341cc584e8740bb171a02baae1b05a87613 Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 19:52:37 +0200 Subject: [PATCH 04/11] Add validate in service to check if data is valid JSON API --- lib/api/services/JsonApiService.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/api/services/JsonApiService.js b/lib/api/services/JsonApiService.js index 2221489..8f00beb 100644 --- a/lib/api/services/JsonApiService.js +++ b/lib/api/services/JsonApiService.js @@ -2,6 +2,7 @@ const _ = require("lodash"); const cleanObject = require('clean-object'); const JSONAPISerializer = require('json-api-serializer'); const Serializer = new JSONAPISerializer(); +const JSONAPIValidator = require('jsonapi-validator').Validator; var findRecords = require('../blueprints/find'); var findOneRecord = require('../blueprints/findone'); @@ -153,5 +154,18 @@ module.exports = { } return errors; + }, + + validate: function(data) { + + var validator = new JSONAPIValidator(); + + try { + validator.validate(data); + + return true; + } catch (e) { + return false; + } } } From 97e3b834b3c72d756baceb64b3e2578c2746270f Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 19:39:26 +0200 Subject: [PATCH 05/11] Add custom response invalidJsonApi to return when invalid payload is given --- lib/api/responses/invalidJsonApi.js | 33 +++++++++++++++++++++++++++++ lib/hook.js | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 lib/api/responses/invalidJsonApi.js diff --git a/lib/api/responses/invalidJsonApi.js b/lib/api/responses/invalidJsonApi.js new file mode 100644 index 0000000..5a3742c --- /dev/null +++ b/lib/api/responses/invalidJsonApi.js @@ -0,0 +1,33 @@ +/** + * 400 (Bad Request) Invalid JSON API Handler + * + * Usage: + * return res.invalidJsonApi(); + * + */ + +module.exports = function invalidJsonApi(data, options) { + + // Get access to `req`, `res`, & `sails` + var req = this.req; + var res = this.res; + var sails = req._sails; + + // Set status code + res.status(400); + + sails.log.verbose('Sending 400 ("Bad Request") invalid JSON API input'); + + return res.json({ + 'errors': [ + { + status: "400", + title: 'Bad request', + detail: 'Invalid JSON API data', + links: { + self: 'http://jsonapi.org/format/' + } + } + ] + }); +}; diff --git a/lib/hook.js b/lib/hook.js index bc11d5a..e732891 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -23,6 +23,7 @@ var responseForbidden = require('./api/responses/forbidden'); var responseServerError = require('./api/responses/serverError'); var responseNegotiate = require('./api/responses/negotiate'); var responseInvalid = require('./api/responses/invalid'); +var responseInvalidJsonApi = require('./api/responses/invalidJsonApi'); function strncmp(a, b, n){ return a.substring(0, n) == b.substring(0, n); @@ -119,6 +120,7 @@ module.exports = function(sails) { sails.hooks.responses.middleware.serverError = responseServerError; sails.hooks.responses.middleware.negotiate = responseNegotiate; sails.hooks.responses.middleware.invalid = responseInvalid; + sails.hooks.responses.middleware.invalidJsonApi = responseInvalidJsonApi; // Load blueprint middleware and continue. loadMiddleware(cb); From 63ba16492ece34f2aabf1416b1e8d708e1d94afb Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 19:49:03 +0200 Subject: [PATCH 06/11] Make sure to validate input payload before proceeding to blueprint --- lib/hook.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/hook.js b/lib/hook.js index e732891..d512a85 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -137,6 +137,11 @@ module.exports = function(sails) { if (strncmp(controller[name]._middlewareType, "BLUEPRINT: ", "BLUEPRINT: ".length) === true) { controller[name] = function(req, res) { + if (req.method !== 'GET' && req.method !== 'DELETE' && + JsonApiService.validate(req.body) === false) { + return res.invalidJsonApi(); + } + req.body = JsonApiService.deserialize(req.body); return middleware(req, res); From 868744352a26fd44cc5b9d171ab355a3170eca01 Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 20:05:38 +0200 Subject: [PATCH 07/11] HOTFIX destroy notFound message to match other error messages --- lib/api/blueprints/destroy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/blueprints/destroy.js b/lib/api/blueprints/destroy.js index 5bf622f..45bc001 100644 --- a/lib/api/blueprints/destroy.js +++ b/lib/api/blueprints/destroy.js @@ -25,7 +25,7 @@ module.exports = function destroyOneRecord(req, res) { query.exec((err, record) => { if (err) return res.serverError(err); - if (!record) return res.notFound('No record found with the specified `id`.'); + if (!record) return res.notFound('No record found with the specified id.'); return Model.destroy(pk).exec((err) => { From fb0c181097a8ed9a54c67e0a0b0afa937ba4789b Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Wed, 6 Jul 2016 20:06:13 +0200 Subject: [PATCH 08/11] Add test to validate a 404 is returned when deleting a not found resource --- .../integration/controllers/Errors.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/dummy/test/integration/controllers/Errors.test.js b/tests/dummy/test/integration/controllers/Errors.test.js index 89409ad..4ad2fde 100644 --- a/tests/dummy/test/integration/controllers/Errors.test.js +++ b/tests/dummy/test/integration/controllers/Errors.test.js @@ -45,6 +45,25 @@ describe('Error handling', function() { }); }); + describe('Delete invalid user /users/42', function() { + it('Should return 404', function (done) { + request(sails.hooks.http.app) + .delete('/users/42') + .expect(404) + .expect(validateJSONapi) + .expect({ + 'errors': [ + { + status: "404", + title: 'Resource not found', + detail: 'No record found with the specified id.' + } + ] + }) + .end(done); + }); + }); + describe('GET categories?invalid=true', function() { it('Should return 400', function(done) { request(sails.hooks.http.app) From a48cf5b4d15d1d0eb54f1ffc1546b9299af349ea Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Mon, 11 Jul 2016 12:11:19 +0200 Subject: [PATCH 09/11] Add context-aware-jsonapi-validator to valid JSON doc in specific context --- lib/context-aware-jsonapi-validator/README | 21 ++ .../create-schema.json | 216 +++++++++++++++++ .../update-schema.json | 217 ++++++++++++++++++ .../validator.js | 25 ++ 4 files changed, 479 insertions(+) create mode 100644 lib/context-aware-jsonapi-validator/README create mode 100644 lib/context-aware-jsonapi-validator/create-schema.json create mode 100644 lib/context-aware-jsonapi-validator/update-schema.json create mode 100644 lib/context-aware-jsonapi-validator/validator.js diff --git a/lib/context-aware-jsonapi-validator/README b/lib/context-aware-jsonapi-validator/README new file mode 100644 index 0000000..9a39f92 --- /dev/null +++ b/lib/context-aware-jsonapi-validator/README @@ -0,0 +1,21 @@ +# context-aware-jsonapi-validator + +A fork from https://github.com/elliotttf/jsonapi-validator with the addition of context checking for JSON API. +In addition to testing JSON to be valid, this module tests given JSON in a specify context. + +For example, a JSON API error object, while valid, is not expected when a server receives data to be updated. + +# Usage + +```` +const jsonApiValidator = require('context-aware-jsonapi-validator'); + +return jsonApiValidator.isValid(doc, context); + +```` + +`doc` is the document to validate against. +`context` is the context whithin which the document is suppoed to be valid. + +Possible values are **CONTEXT_UPDATE**, **CONTEXT_CREATE** and undefined. +A context with the value *undefined* validation the document to be a valid JSON API response. \ No newline at end of file diff --git a/lib/context-aware-jsonapi-validator/create-schema.json b/lib/context-aware-jsonapi-validator/create-schema.json new file mode 100644 index 0000000..5825f2a --- /dev/null +++ b/lib/context-aware-jsonapi-validator/create-schema.json @@ -0,0 +1,216 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "JSON API Schema", + "description": "This is a schema for updating resource in the JSON API format. For more, see http://jsonapi.org", + "oneOf": [ + { + "$ref": "#/definitions/success" + } + ], + + "definitions": { + "success": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/definitions/data" + }, + "meta": { + "$ref": "#/definitions/meta" + }, + "jsonapi": { + "$ref": "#/definitions/jsonapi" + } + }, + "additionalProperties": false + }, + + "meta": { + "description": "Non-standard meta-information that can not be represented as an attribute or relationship.", + "type": "object", + "additionalProperties": true + }, + "data": { + "description": "he PATCH request MUST include a single resource object as primary data.", + "oneOf": [ + { + "$ref": "#/definitions/resource" + } + ] + }, + "resource": { + "description": "\"Resource objects\" appear in a JSON API document to represent resources.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/definitions/attributes" + }, + "relationships": { + "$ref": "#/definitions/relationships" + }, + "links": { + "$ref": "#/definitions/links" + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + }, + + "links": { + "description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.", + "type": "object", + "properties": { + "self": { + "description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.", + "type": "string", + "format": "uri" + }, + "related": { + "$ref": "#/definitions/link" + } + }, + "additionalProperties": true + }, + "link": { + "description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.", + "oneOf": [ + { + "description": "A string containing the link's URL.", + "type": "string", + "format": "uri" + }, + { + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "A string containing the link's URL.", + "type": "string", + "format": "uri" + }, + "meta": { + "$ref": "#/definitions/meta" + } + } + } + ] + }, + + "attributes": { + "description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.", + "type": "object", + "patternProperties": { + "^(?!relationships$|links$)\\w[-\\w_]*$": { + "description": "Attributes may contain any valid JSON value." + } + }, + "additionalProperties": false + }, + + "relationships": { + "description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.", + "type": "object", + "patternProperties": { + "^\\w[-\\w_]*$": { + "properties": { + "links": { + "$ref": "#/definitions/links" + }, + "data": { + "description": "Member, whose value represents \"resource linkage\".", + "oneOf": [ + { + "$ref": "#/definitions/relationshipToOne" + }, + { + "$ref": "#/definitions/relationshipToMany" + } + ] + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "relationshipToOne": { + "description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.", + "anyOf": [ + { + "$ref": "#/definitions/empty" + }, + { + "$ref": "#/definitions/linkage" + } + ] + }, + "relationshipToMany": { + "description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.", + "type": "array", + "items": { + "$ref": "#/definitions/linkage" + }, + "uniqueItems": true + }, + "empty": { + "description": "Describes an empty to-one relationship.", + "type": ["object", "null"], + "properties": {}, + "additionalProperties": false + }, + "linkage": { + "description": "The \"type\" and \"id\" to non-empty members.", + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + }, + + "jsonapi": { + "description": "An object describing the server's implementation", + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + } + + } +} diff --git a/lib/context-aware-jsonapi-validator/update-schema.json b/lib/context-aware-jsonapi-validator/update-schema.json new file mode 100644 index 0000000..5acfecb --- /dev/null +++ b/lib/context-aware-jsonapi-validator/update-schema.json @@ -0,0 +1,217 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "JSON API Schema", + "description": "This is a schema for updating resource in the JSON API format. For more, see http://jsonapi.org", + "oneOf": [ + { + "$ref": "#/definitions/success" + } + ], + + "definitions": { + "success": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/definitions/data" + }, + "meta": { + "$ref": "#/definitions/meta" + }, + "jsonapi": { + "$ref": "#/definitions/jsonapi" + } + }, + "additionalProperties": false + }, + + "meta": { + "description": "Non-standard meta-information that can not be represented as an attribute or relationship.", + "type": "object", + "additionalProperties": true + }, + "data": { + "description": "he PATCH request MUST include a single resource object as primary data.", + "oneOf": [ + { + "$ref": "#/definitions/resource" + } + ] + }, + "resource": { + "description": "\"Resource objects\" appear in a JSON API document to represent resources.", + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/definitions/attributes" + }, + "relationships": { + "$ref": "#/definitions/relationships" + }, + "links": { + "$ref": "#/definitions/links" + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + }, + + "links": { + "description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.", + "type": "object", + "properties": { + "self": { + "description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.", + "type": "string", + "format": "uri" + }, + "related": { + "$ref": "#/definitions/link" + } + }, + "additionalProperties": true + }, + "link": { + "description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.", + "oneOf": [ + { + "description": "A string containing the link's URL.", + "type": "string", + "format": "uri" + }, + { + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "A string containing the link's URL.", + "type": "string", + "format": "uri" + }, + "meta": { + "$ref": "#/definitions/meta" + } + } + } + ] + }, + + "attributes": { + "description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.", + "type": "object", + "patternProperties": { + "^(?!relationships$|links$)\\w[-\\w_]*$": { + "description": "Attributes may contain any valid JSON value." + } + }, + "additionalProperties": false + }, + + "relationships": { + "description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.", + "type": "object", + "patternProperties": { + "^\\w[-\\w_]*$": { + "properties": { + "links": { + "$ref": "#/definitions/links" + }, + "data": { + "description": "Member, whose value represents \"resource linkage\".", + "oneOf": [ + { + "$ref": "#/definitions/relationshipToOne" + }, + { + "$ref": "#/definitions/relationshipToMany" + } + ] + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "relationshipToOne": { + "description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.", + "anyOf": [ + { + "$ref": "#/definitions/empty" + }, + { + "$ref": "#/definitions/linkage" + } + ] + }, + "relationshipToMany": { + "description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.", + "type": "array", + "items": { + "$ref": "#/definitions/linkage" + }, + "uniqueItems": true + }, + "empty": { + "description": "Describes an empty to-one relationship.", + "type": ["object", "null"], + "properties": {}, + "additionalProperties": false + }, + "linkage": { + "description": "The \"type\" and \"id\" to non-empty members.", + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + }, + + "jsonapi": { + "description": "An object describing the server's implementation", + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/meta" + } + }, + "additionalProperties": false + } + + } +} diff --git a/lib/context-aware-jsonapi-validator/validator.js b/lib/context-aware-jsonapi-validator/validator.js new file mode 100644 index 0000000..7995d90 --- /dev/null +++ b/lib/context-aware-jsonapi-validator/validator.js @@ -0,0 +1,25 @@ +const Validator = require('jsonapi-validator').Validator; +const updateValidator = new Validator(require('./update-schema.json')); +const createValidator = new Validator(require('./create-schema.json')); +const defaultValidator = new Validator(); + +module.exports = { + + CONTEXT_ANY: 0, + CONTEXT_UPDATE: 1, + CONTEXT_CREATE: 2, + + isValid: function(doc, schema) { + + var validatorStrategy = undefined; + + if (schema === this.CONTEXT_UPDATE) + validatorStrategy = updateValidator; + else if (schema === this.CONTEXT_CREATE) + validatorStrategy = createValidator; + else + validatorStrategy = defaultValidator; + + return validatorStrategy.isValid(doc); + } +}; From f831dd79265794f6b313639adc0b5ef49b27537a Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Mon, 11 Jul 2016 12:11:39 +0200 Subject: [PATCH 10/11] JsonApiService.validate can validate document given a context --- lib/api/services/JsonApiService.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/api/services/JsonApiService.js b/lib/api/services/JsonApiService.js index 8f00beb..36b695a 100644 --- a/lib/api/services/JsonApiService.js +++ b/lib/api/services/JsonApiService.js @@ -1,8 +1,8 @@ const _ = require("lodash"); const cleanObject = require('clean-object'); const JSONAPISerializer = require('json-api-serializer'); +const jsonApiValidator = require('../../context-aware-jsonapi-validator/validator'); const Serializer = new JSONAPISerializer(); -const JSONAPIValidator = require('jsonapi-validator').Validator; var findRecords = require('../blueprints/find'); var findOneRecord = require('../blueprints/findone'); @@ -156,16 +156,8 @@ module.exports = { return errors; }, - validate: function(data) { + validate: function(doc, strategy) { - var validator = new JSONAPIValidator(); - - try { - validator.validate(data); - - return true; - } catch (e) { - return false; - } + return jsonApiValidator.isValid(doc, strategy); } } From 2a06020fa389dd182f5d830713adb150811147dd Mon Sep 17 00:00:00 2001 From: Olivier Berthonneau Date: Mon, 11 Jul 2016 12:13:39 +0200 Subject: [PATCH 11/11] All input json api data are validated before proceeding --- lib/hook.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/hook.js b/lib/hook.js index d512a85..6b7a3ae 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -15,6 +15,7 @@ var BlueprintController = { , populate: require('./api/blueprints/populate') }; var JsonApiService = require('./api/services/JsonApiService'); +var jsonApiValidator = require('./context-aware-jsonapi-validator/validator'); var responseOk = require('./api/responses/ok'); var responseCreated = require('./api/responses/created'); var responseNotFound = require('./api/responses/notFound'); @@ -137,9 +138,12 @@ module.exports = function(sails) { if (strncmp(controller[name]._middlewareType, "BLUEPRINT: ", "BLUEPRINT: ".length) === true) { controller[name] = function(req, res) { - if (req.method !== 'GET' && req.method !== 'DELETE' && - JsonApiService.validate(req.body) === false) { - return res.invalidJsonApi(); + if (req.method === 'POST' || req.method === 'PATCH') { + + var context = (req.method === 'POST') ? jsonApiValidator.CONTEXT_CREATE : jsonApiValidator.CONTEXT_UPDATE; + + if (JsonApiService.validate(req.body, context) === false) + return res.invalidJsonApi(); } req.body = JsonApiService.deserialize(req.body);