Skip to content

Commit e6b6858

Browse files
authored
Merge pull request #16 from dynamiccast/check-json-api-inputs
Check json api inputs
2 parents aa1b49a + 2a06020 commit e6b6858

File tree

10 files changed

+582
-1
lines changed

10 files changed

+582
-1
lines changed

lib/api/blueprints/destroy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module.exports = function destroyOneRecord(req, res) {
2525
query.exec((err, record) => {
2626

2727
if (err) return res.serverError(err);
28-
if (!record) return res.notFound('No record found with the specified `id`.');
28+
if (!record) return res.notFound('No record found with the specified id.');
2929

3030
return Model.destroy(pk).exec((err) => {
3131

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* 400 (Bad Request) Invalid JSON API Handler
3+
*
4+
* Usage:
5+
* return res.invalidJsonApi();
6+
*
7+
*/
8+
9+
module.exports = function invalidJsonApi(data, options) {
10+
11+
// Get access to `req`, `res`, & `sails`
12+
var req = this.req;
13+
var res = this.res;
14+
var sails = req._sails;
15+
16+
// Set status code
17+
res.status(400);
18+
19+
sails.log.verbose('Sending 400 ("Bad Request") invalid JSON API input');
20+
21+
return res.json({
22+
'errors': [
23+
{
24+
status: "400",
25+
title: 'Bad request',
26+
detail: 'Invalid JSON API data',
27+
links: {
28+
self: 'http://jsonapi.org/format/'
29+
}
30+
}
31+
]
32+
});
33+
};

lib/api/services/JsonApiService.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const _ = require("lodash");
22
const cleanObject = require('clean-object');
33
const JSONAPISerializer = require('json-api-serializer');
4+
const jsonApiValidator = require('../../context-aware-jsonapi-validator/validator');
45
const Serializer = new JSONAPISerializer();
56

67
var findRecords = require('../blueprints/find');
@@ -153,5 +154,10 @@ module.exports = {
153154
}
154155

155156
return errors;
157+
},
158+
159+
validate: function(doc, strategy) {
160+
161+
return jsonApiValidator.isValid(doc, strategy);
156162
}
157163
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# context-aware-jsonapi-validator
2+
3+
A fork from https://github.com/elliotttf/jsonapi-validator with the addition of context checking for JSON API.
4+
In addition to testing JSON to be valid, this module tests given JSON in a specify context.
5+
6+
For example, a JSON API error object, while valid, is not expected when a server receives data to be updated.
7+
8+
# Usage
9+
10+
````
11+
const jsonApiValidator = require('context-aware-jsonapi-validator');
12+
13+
return jsonApiValidator.isValid(doc, context);
14+
15+
````
16+
17+
`doc` is the document to validate against.
18+
`context` is the context whithin which the document is suppoed to be valid.
19+
20+
Possible values are **CONTEXT_UPDATE**, **CONTEXT_CREATE** and undefined.
21+
A context with the value *undefined* validation the document to be a valid JSON API response.
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"title": "JSON API Schema",
4+
"description": "This is a schema for updating resource in the JSON API format. For more, see http://jsonapi.org",
5+
"oneOf": [
6+
{
7+
"$ref": "#/definitions/success"
8+
}
9+
],
10+
11+
"definitions": {
12+
"success": {
13+
"type": "object",
14+
"required": [
15+
"data"
16+
],
17+
"properties": {
18+
"data": {
19+
"$ref": "#/definitions/data"
20+
},
21+
"meta": {
22+
"$ref": "#/definitions/meta"
23+
},
24+
"jsonapi": {
25+
"$ref": "#/definitions/jsonapi"
26+
}
27+
},
28+
"additionalProperties": false
29+
},
30+
31+
"meta": {
32+
"description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
33+
"type": "object",
34+
"additionalProperties": true
35+
},
36+
"data": {
37+
"description": "he PATCH request MUST include a single resource object as primary data.",
38+
"oneOf": [
39+
{
40+
"$ref": "#/definitions/resource"
41+
}
42+
]
43+
},
44+
"resource": {
45+
"description": "\"Resource objects\" appear in a JSON API document to represent resources.",
46+
"type": "object",
47+
"required": [
48+
"type"
49+
],
50+
"properties": {
51+
"type": {
52+
"type": "string"
53+
},
54+
"id": {
55+
"type": "string"
56+
},
57+
"attributes": {
58+
"$ref": "#/definitions/attributes"
59+
},
60+
"relationships": {
61+
"$ref": "#/definitions/relationships"
62+
},
63+
"links": {
64+
"$ref": "#/definitions/links"
65+
},
66+
"meta": {
67+
"$ref": "#/definitions/meta"
68+
}
69+
},
70+
"additionalProperties": false
71+
},
72+
73+
"links": {
74+
"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.",
75+
"type": "object",
76+
"properties": {
77+
"self": {
78+
"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.",
79+
"type": "string",
80+
"format": "uri"
81+
},
82+
"related": {
83+
"$ref": "#/definitions/link"
84+
}
85+
},
86+
"additionalProperties": true
87+
},
88+
"link": {
89+
"description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
90+
"oneOf": [
91+
{
92+
"description": "A string containing the link's URL.",
93+
"type": "string",
94+
"format": "uri"
95+
},
96+
{
97+
"type": "object",
98+
"required": [
99+
"href"
100+
],
101+
"properties": {
102+
"href": {
103+
"description": "A string containing the link's URL.",
104+
"type": "string",
105+
"format": "uri"
106+
},
107+
"meta": {
108+
"$ref": "#/definitions/meta"
109+
}
110+
}
111+
}
112+
]
113+
},
114+
115+
"attributes": {
116+
"description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
117+
"type": "object",
118+
"patternProperties": {
119+
"^(?!relationships$|links$)\\w[-\\w_]*$": {
120+
"description": "Attributes may contain any valid JSON value."
121+
}
122+
},
123+
"additionalProperties": false
124+
},
125+
126+
"relationships": {
127+
"description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
128+
"type": "object",
129+
"patternProperties": {
130+
"^\\w[-\\w_]*$": {
131+
"properties": {
132+
"links": {
133+
"$ref": "#/definitions/links"
134+
},
135+
"data": {
136+
"description": "Member, whose value represents \"resource linkage\".",
137+
"oneOf": [
138+
{
139+
"$ref": "#/definitions/relationshipToOne"
140+
},
141+
{
142+
"$ref": "#/definitions/relationshipToMany"
143+
}
144+
]
145+
},
146+
"meta": {
147+
"$ref": "#/definitions/meta"
148+
}
149+
},
150+
"additionalProperties": false
151+
}
152+
},
153+
"additionalProperties": false
154+
},
155+
"relationshipToOne": {
156+
"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.",
157+
"anyOf": [
158+
{
159+
"$ref": "#/definitions/empty"
160+
},
161+
{
162+
"$ref": "#/definitions/linkage"
163+
}
164+
]
165+
},
166+
"relationshipToMany": {
167+
"description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
168+
"type": "array",
169+
"items": {
170+
"$ref": "#/definitions/linkage"
171+
},
172+
"uniqueItems": true
173+
},
174+
"empty": {
175+
"description": "Describes an empty to-one relationship.",
176+
"type": ["object", "null"],
177+
"properties": {},
178+
"additionalProperties": false
179+
},
180+
"linkage": {
181+
"description": "The \"type\" and \"id\" to non-empty members.",
182+
"type": "object",
183+
"required": [
184+
"type",
185+
"id"
186+
],
187+
"properties": {
188+
"type": {
189+
"type": "string"
190+
},
191+
"id": {
192+
"type": "string"
193+
},
194+
"meta": {
195+
"$ref": "#/definitions/meta"
196+
}
197+
},
198+
"additionalProperties": false
199+
},
200+
201+
"jsonapi": {
202+
"description": "An object describing the server's implementation",
203+
"type": "object",
204+
"properties": {
205+
"version": {
206+
"type": "string"
207+
},
208+
"meta": {
209+
"$ref": "#/definitions/meta"
210+
}
211+
},
212+
"additionalProperties": false
213+
}
214+
215+
}
216+
}

0 commit comments

Comments
 (0)