Skip to content

Commit f58ed42

Browse files
committed
tests: add jsonapi schema validation where appropriate
Fixes #25
1 parent 4e5c29c commit f58ed42

File tree

4 files changed

+410
-1
lines changed

4 files changed

+410
-1
lines changed

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
"illuminate/pagination" : "5.1.*"
1919
},
2020
"require-dev": {
21-
"phpunit/phpunit": "4.*"
21+
"phpunit/phpunit": "4.*",
22+
"justinrainbow/json-schema": "^1.5"
2223
},
2324
"autoload": {
2425
"psr-0": {
2526
"EchoIt\\JsonApi\\": "src/"
27+
},
28+
"psr-4": {
29+
"EchoIt\\JsonApi\\Tests\\": "tests/"
2630
}
2731
}
2832
}

resources/jsonapi-schema-1.0.json

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"title": "JSON API Schema",
4+
"description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
5+
"oneOf": [
6+
{
7+
"$ref": "#/definitions/success"
8+
},
9+
{
10+
"$ref": "#/definitions/failure"
11+
},
12+
{
13+
"$ref": "#/definitions/info"
14+
}
15+
],
16+
17+
"definitions": {
18+
"success": {
19+
"type": "object",
20+
"required": [
21+
"data"
22+
],
23+
"properties": {
24+
"data": {
25+
"$ref": "#/definitions/data"
26+
},
27+
"included": {
28+
"description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".",
29+
"type": "array",
30+
"items": {
31+
"$ref": "#/definitions/resource"
32+
},
33+
"uniqueItems": true
34+
},
35+
"meta": {
36+
"$ref": "#/definitions/meta"
37+
},
38+
"links": {
39+
"description": "Link members related to the primary data.",
40+
"allOf": [
41+
{
42+
"$ref": "#/definitions/links"
43+
},
44+
{
45+
"$ref": "#/definitions/pagination"
46+
}
47+
]
48+
},
49+
"jsonapi": {
50+
"$ref": "#/definitions/jsonapi"
51+
}
52+
},
53+
"additionalProperties": false
54+
},
55+
"failure": {
56+
"type": "object",
57+
"required": [
58+
"errors"
59+
],
60+
"properties": {
61+
"errors": {
62+
"type": "array",
63+
"items": {
64+
"$ref": "#/definitions/error"
65+
},
66+
"uniqueItems": true
67+
},
68+
"meta": {
69+
"$ref": "#/definitions/meta"
70+
},
71+
"jsonapi": {
72+
"$ref": "#/definitions/jsonapi"
73+
}
74+
},
75+
"additionalProperties": false
76+
},
77+
"info": {
78+
"type": "object",
79+
"required": [
80+
"meta"
81+
],
82+
"properties": {
83+
"meta": {
84+
"$ref": "#/definitions/meta"
85+
},
86+
"links": {
87+
"$ref": "#/definitions/links"
88+
},
89+
"jsonapi": {
90+
"$ref": "#/definitions/jsonapi"
91+
}
92+
},
93+
"additionalProperties": false
94+
},
95+
96+
"meta": {
97+
"description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
98+
"type": "object",
99+
"additionalProperties": true
100+
},
101+
"data": {
102+
"description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.",
103+
"oneOf": [
104+
{
105+
"$ref": "#/definitions/resource"
106+
},
107+
{
108+
"description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.",
109+
"type": "array",
110+
"items": {
111+
"$ref": "#/definitions/resource"
112+
},
113+
"uniqueItems": true
114+
}
115+
]
116+
},
117+
"resource": {
118+
"description": "\"Resource objects\" appear in a JSON API document to represent resources.",
119+
"type": "object",
120+
"required": [
121+
"type",
122+
"id"
123+
],
124+
"properties": {
125+
"type": {
126+
"type": "string"
127+
},
128+
"id": {
129+
"type": "string"
130+
},
131+
"attributes": {
132+
"$ref": "#/definitions/attributes"
133+
},
134+
"relationships": {
135+
"$ref": "#/definitions/relationships"
136+
},
137+
"links": {
138+
"$ref": "#/definitions/links"
139+
},
140+
"meta": {
141+
"$ref": "#/definitions/meta"
142+
}
143+
},
144+
"additionalProperties": false
145+
},
146+
147+
"links": {
148+
"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.",
149+
"type": "object",
150+
"properties": {
151+
"self": {
152+
"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.",
153+
"type": "string",
154+
"format": "uri"
155+
},
156+
"related": {
157+
"$ref": "#/definitions/link"
158+
}
159+
},
160+
"additionalProperties": true
161+
},
162+
"link": {
163+
"description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
164+
"oneOf": [
165+
{
166+
"description": "A string containing the link's URL.",
167+
"type": "string",
168+
"format": "uri"
169+
},
170+
{
171+
"type": "object",
172+
"required": [
173+
"href"
174+
],
175+
"properties": {
176+
"href": {
177+
"description": "A string containing the link's URL.",
178+
"type": "string",
179+
"format": "uri"
180+
},
181+
"meta": {
182+
"$ref": "#/definitions/meta"
183+
}
184+
}
185+
}
186+
]
187+
},
188+
189+
"attributes": {
190+
"description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
191+
"type": "object",
192+
"patternProperties": {
193+
"^(?!relationships$|links$)\\w[-\\w_]*$": {
194+
"description": "Attributes may contain any valid JSON value."
195+
}
196+
},
197+
"additionalProperties": false
198+
},
199+
200+
"relationships": {
201+
"description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
202+
"type": "object",
203+
"patternProperties": {
204+
"^\\w[-\\w_]*$": {
205+
"properties": {
206+
"links": {
207+
"$ref": "#/definitions/links"
208+
},
209+
"data": {
210+
"description": "Member, whose value represents \"resource linkage\".",
211+
"oneOf": [
212+
{
213+
"$ref": "#/definitions/relationshipToOne"
214+
},
215+
{
216+
"$ref": "#/definitions/relationshipToMany"
217+
}
218+
]
219+
},
220+
"meta": {
221+
"$ref": "#/definitions/meta"
222+
}
223+
},
224+
"additionalProperties": false
225+
}
226+
},
227+
"additionalProperties": false
228+
},
229+
"relationshipToOne": {
230+
"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.",
231+
"anyOf": [
232+
{
233+
"$ref": "#/definitions/empty"
234+
},
235+
{
236+
"$ref": "#/definitions/linkage"
237+
}
238+
]
239+
},
240+
"relationshipToMany": {
241+
"description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
242+
"type": "array",
243+
"items": {
244+
"$ref": "#/definitions/linkage"
245+
},
246+
"uniqueItems": true
247+
},
248+
"empty": {
249+
"description": "Describes an empty to-one relationship.",
250+
"type": "null"
251+
},
252+
"linkage": {
253+
"description": "The \"type\" and \"id\" to non-empty members.",
254+
"type": "object",
255+
"required": [
256+
"type",
257+
"id"
258+
],
259+
"properties": {
260+
"type": {
261+
"type": "string"
262+
},
263+
"id": {
264+
"type": "string"
265+
},
266+
"meta": {
267+
"$ref": "#/definitions/meta"
268+
}
269+
},
270+
"additionalProperties": false
271+
},
272+
"pagination": {
273+
"type": "object",
274+
"properties": {
275+
"first": {
276+
"description": "The first page of data",
277+
"oneOf": [
278+
{ "type": "string", "format": "uri" },
279+
{ "type": "null" }
280+
]
281+
},
282+
"last": {
283+
"description": "The last page of data",
284+
"oneOf": [
285+
{ "type": "string", "format": "uri" },
286+
{ "type": "null" }
287+
]
288+
},
289+
"prev": {
290+
"description": "The previous page of data",
291+
"oneOf": [
292+
{ "type": "string", "format": "uri" },
293+
{ "type": "null" }
294+
]
295+
},
296+
"next": {
297+
"description": "The next page of data",
298+
"oneOf": [
299+
{ "type": "string", "format": "uri" },
300+
{ "type": "null" }
301+
]
302+
}
303+
}
304+
},
305+
306+
"jsonapi": {
307+
"description": "An object describing the server's implementation",
308+
"type": "object",
309+
"properties": {
310+
"version": {
311+
"type": "string"
312+
},
313+
"meta": {
314+
"$ref": "#/definitions/meta"
315+
}
316+
},
317+
"additionalProperties": false
318+
},
319+
320+
"error": {
321+
"type": "object",
322+
"properties": {
323+
"id": {
324+
"description": "A unique identifier for this particular occurrence of the problem.",
325+
"type": "string"
326+
},
327+
"links": {
328+
"$ref": "#/definitions/links"
329+
},
330+
"status": {
331+
"description": "The HTTP status code applicable to this problem, expressed as a string value.",
332+
"type": "string"
333+
},
334+
"code": {
335+
"description": "An application-specific error code, expressed as a string value.",
336+
"type": "string"
337+
},
338+
"title": {
339+
"description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
340+
"type": "string"
341+
},
342+
"detail": {
343+
"description": "A human-readable explanation specific to this occurrence of the problem.",
344+
"type": "string"
345+
},
346+
"source": {
347+
"type": "object",
348+
"properties": {
349+
"pointer": {
350+
"description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].",
351+
"type": "string"
352+
},
353+
"parameter": {
354+
"description": "A string indicating which query parameter caused the error.",
355+
"type": "string"
356+
}
357+
}
358+
},
359+
"meta": {
360+
"$ref": "#/definitions/meta"
361+
}
362+
},
363+
"additionalProperties": false
364+
}
365+
}
366+
}

0 commit comments

Comments
 (0)