json_api_conformant 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4634ddceab8a179d9c13de30a94cf8592db96bf9
4
- data.tar.gz: 66ca7f6573f8bb44f5badf9dd29dda5de8593bd9
3
+ metadata.gz: fc3bcb951985dd2a665cdb84f7b1c6ce2c539b86
4
+ data.tar.gz: 88e96d8554af56e995f8b3dca3161473209e31c5
5
5
  SHA512:
6
- metadata.gz: f5a94c9cad6f10c1c64d5e5c28e32a249b366b83a27264d6e1522056808eb5a2c68f2cfb050aaf853a7012f67c5644f82eca6d74a02636f827c07bc70d111997
7
- data.tar.gz: 0e09e145ab952ac4eab546015bf4d3cc61397e460838a773a21f18ef4f430f00ed4c630fa9d2ce7f2df5beeda1415cd90571683bf8337eeb334fa76397271acb
6
+ metadata.gz: 7808472e832d55a99c7daade9c44a370a66f443bf353b775d60a53781e86e41ea6f764473f91c288c359403f16eb90e2d819adfc3ab3364e7dc8e84a737e3b9b
7
+ data.tar.gz: 3749fa0fc26839e391630fc0d61e4e506036b1441dfa2f42474f64cf039d5a8b34961d0595eb0d519b0a688aed9e3c6d7a176f7ffb3f89b57ffe0116c5a750b1
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml CHANGED
@@ -1,12 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.1
3
+ - 2.4.1
6
4
  - ruby-head
7
- - jruby-1.7.9
8
- - jruby-head
9
- - rbx-2.2.7
10
- matrix:
11
- allow_failures:
12
- - rvm: jruby-head
@@ -0,0 +1,74 @@
1
+ # Contributor Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, sexual identity and
10
+ orientation, or sexual proclivities between consenting adults.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project maintainer at [sebasoga@gmail.com]. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4.1,
71
+ available at [http://contributor-covenant.org/version/1/4/1][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Sebastian Sogamoso
1
+ Copyright (c) 2017 Sebastian Sogamoso
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -2,19 +2,19 @@
2
2
  [![Build Status](https://travis-ci.org/sebasoga/json_api_conformant.svg?branch=master)](https://travis-ci.org/sebasoga/json_api_conformant)
3
3
  [![Code Climate](https://codeclimate.com/github/sebasoga/json_api_conformant/badges/gpa.svg)](https://codeclimate.com/github/sebasoga/json_api_conformant)
4
4
 
5
- When building an API in JSON it is important to follow conventions for the so
6
- that your system clients know how to send a request for the available resources
7
- to be fetched or modified and how your system will respond to those requests.
5
+ When building an API in JSON it is important to follow conventions so that the
6
+ clients know how what to expect in the response when operating on the available
7
+ resources.
8
8
 
9
- JSON API Conformant provides a narrow interface for validating JSON objects
10
- against a [JSON API](http://jsonapi.org/) conforming
11
- [JSON API schema](http://jsonapi.org/schema) and provides a custom RSpec
9
+ JSON API Conformant provides a narrow interface for validating JSON objects
10
+ against the [JSON API specification](http://jsonapi.org/) using
11
+ [the official schema](http://jsonapi.org/schema) and provides a custom RSpec
12
12
  matcher for use in your tests.
13
13
 
14
- **Important:** JSON API is a work in progress. The base schema is not a perfect
15
- document. The fact that a JSON document validates against this schema, it does
16
- not necessarily mean it is a valid JSON API document. The schema is provided by
17
- JSON API for a base level sanity check.
14
+ **Important:** Currently v1.0 specification is used as the default base schema.
15
+ The base schema is not a perfect document. The fact that a JSON document
16
+ validates against this schema, it does not necessarily mean it is a valid JSON
17
+ API document. The schema is provided by JSON API for a base level sanity check.
18
18
 
19
19
  ## Installation
20
20
 
@@ -36,8 +36,8 @@ Or install it yourself as:
36
36
 
37
37
  Validate if your JSON object is JSON API conformant.
38
38
  ```ruby
39
- valid_schema = {"posts" => [{"id" => "1"}]}
40
- invalid_schema = {"comments" => "Nice gem!"}
39
+ valid_schema = { "data" => [{ "type" => "posts", "id" => "1" }] }
40
+ invalid_schema = { "data" => [{ "posts" => "1" }] }
41
41
 
42
42
  JSON::API::Conformant.valid?(valid_schema) # => true
43
43
  JSON::API::Conformant.valid?(invalid_schema) # => false
@@ -45,30 +45,30 @@ JSON::API::Conformant.valid?(invalid_schema) # => false
45
45
 
46
46
  Get errors when your JSON object is JSON API not conformant.
47
47
  ```ruby
48
- valid_schema = {"posts" => [{"id" => "1"}]}
49
- invalid_schema = {"comments" => "Nice gem!"}
48
+ valid_schema = { "data" => [{ "type" => "posts", "id" => "1" }] }
49
+ invalid_schema = { "data" => [{ "posts" => "1" }] }
50
50
 
51
51
  JSON::API::Conformant.validate(valid_schema) # => []
52
- JSON::API::Conformant.validate(invalid_schema) # => ["The property '#/comments' of type String did not match the..."]
52
+ JSON::API::Conformant.validate(invalid_schema) # => ["The property '#/' of type object did not match any of the..."]
53
53
  ```
54
54
 
55
- JSON API Conformant wraps [json-schema](https://github.com/hoxworth/json-schema),
55
+ JSON API Conformant wraps [json-schema](https://github.com/hoxworth/json-schema),
56
56
  so other options that validator accepts will work here too.
57
57
  ```ruby
58
- schema = {"posts" => [{"id" => "1"}]}
58
+ schema = { "data" => [{ "posts" => "1" }] }
59
59
 
60
- JSON::API::Conformant.valid?(valid_schema, insert_defaults: true)
61
- JSON::API::Conformant.validate(valid_schema, errors_as_objects: true)
60
+ JSON::API::Conformant.valid?(schema, insert_defaults: true)
61
+ JSON::API::Conformant.validate(schema, errors_as_objects: true)
62
62
  ```
63
63
 
64
64
 
65
65
  ### RSpec Matcher
66
- Only tested with RSpec 3.
66
+ Only tested for RSpec 3.
67
67
 
68
68
  It is pretty straighword to use.
69
69
  ```ruby
70
70
  it "validates that's JSON API conformant" do
71
- data = {"posts" => [{"id" => "1"}]}
71
+ data = { "data" => [{ "posts" => "1" }] }
72
72
  expect(data).to be_json_api_conformant
73
73
  end
74
74
  ```
@@ -82,6 +82,9 @@ end
82
82
  5. Push to the branch (`git push origin my-new-feature`)
83
83
  6. Create a new Pull Request
84
84
 
85
+ Everyone interacting in this codebase and issue tracker is expected to follow
86
+ the [code of conduct](https://github.com/sebasoga/json_api_conformant/blob/master/CODE_OF_CONDUCT.md).
87
+
85
88
  ## License
86
89
 
87
90
  See [LICENSE](https://github.com/sebasoga/json_api_conformant/blob/master/LICENSE.txt)
@@ -18,8 +18,8 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_dependency "rspec", "~> 3.0"
24
- spec.add_dependency "json-schema", "~> 2.2"
21
+ spec.add_development_dependency "bundler", "~> 1.14"
22
+ spec.add_development_dependency "rake", "~> 12.0"
23
+ spec.add_dependency "rspec", "~> 3.5"
24
+ spec.add_dependency "json-schema", "~> 2.8"
25
25
  end
@@ -3,15 +3,15 @@ require 'json-schema'
3
3
  module JSON
4
4
  module API
5
5
  class Conformant
6
- SCHEMA_VERSION = 'draft'
6
+ DEFAULT_SCHEMA_VERSION = '1.0'
7
7
 
8
8
  class << self
9
- def valid?(data, options={})
10
- validator.validate(schema, data, options)
9
+ def valid?(data, version: DEFAULT_SCHEMA_VERSION, **options)
10
+ validator.validate(schema(version), data, options)
11
11
  end
12
12
 
13
- def validate(data, options={})
14
- validator.fully_validate(schema, data, options)
13
+ def validate(data, version: DEFAULT_SCHEMA_VERSION, **options)
14
+ validator.fully_validate(schema(version), data, options)
15
15
  end
16
16
 
17
17
  private
@@ -20,10 +20,10 @@ module JSON
20
20
  JSON::Validator
21
21
  end
22
22
 
23
- def schema
23
+ def schema(version)
24
24
  File.join(Pathname.new(File.dirname(__FILE__)).parent.parent,
25
25
  'schemas',
26
- "#{SCHEMA_VERSION}.json"
26
+ "#{version}.json"
27
27
  )
28
28
  end
29
29
  end
@@ -1,7 +1,7 @@
1
1
  module JSON
2
2
  module API
3
3
  class Conformant
4
- VERSION = "0.0.2"
4
+ VERSION = "1.0.0"
5
5
  end
6
6
  end
7
7
  end
data/schemas/1.0.json ADDED
@@ -0,0 +1,370 @@
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
+ "description": "null if the request is one that might correspond to a single resource, but doesn't currently.",
117
+ "type": "null"
118
+ }
119
+ ]
120
+ },
121
+ "resource": {
122
+ "description": "\"Resource objects\" appear in a JSON API document to represent resources.",
123
+ "type": "object",
124
+ "required": [
125
+ "type",
126
+ "id"
127
+ ],
128
+ "properties": {
129
+ "type": {
130
+ "type": "string"
131
+ },
132
+ "id": {
133
+ "type": "string"
134
+ },
135
+ "attributes": {
136
+ "$ref": "#/definitions/attributes"
137
+ },
138
+ "relationships": {
139
+ "$ref": "#/definitions/relationships"
140
+ },
141
+ "links": {
142
+ "$ref": "#/definitions/links"
143
+ },
144
+ "meta": {
145
+ "$ref": "#/definitions/meta"
146
+ }
147
+ },
148
+ "additionalProperties": false
149
+ },
150
+
151
+ "links": {
152
+ "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.",
153
+ "type": "object",
154
+ "properties": {
155
+ "self": {
156
+ "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.",
157
+ "type": "string",
158
+ "format": "uri"
159
+ },
160
+ "related": {
161
+ "$ref": "#/definitions/link"
162
+ }
163
+ },
164
+ "additionalProperties": true
165
+ },
166
+ "link": {
167
+ "description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
168
+ "oneOf": [
169
+ {
170
+ "description": "A string containing the link's URL.",
171
+ "type": "string",
172
+ "format": "uri"
173
+ },
174
+ {
175
+ "type": "object",
176
+ "required": [
177
+ "href"
178
+ ],
179
+ "properties": {
180
+ "href": {
181
+ "description": "A string containing the link's URL.",
182
+ "type": "string",
183
+ "format": "uri"
184
+ },
185
+ "meta": {
186
+ "$ref": "#/definitions/meta"
187
+ }
188
+ }
189
+ }
190
+ ]
191
+ },
192
+
193
+ "attributes": {
194
+ "description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
195
+ "type": "object",
196
+ "patternProperties": {
197
+ "^(?!relationships$|links$)\\w[-\\w_]*$": {
198
+ "description": "Attributes may contain any valid JSON value."
199
+ }
200
+ },
201
+ "additionalProperties": false
202
+ },
203
+
204
+ "relationships": {
205
+ "description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
206
+ "type": "object",
207
+ "patternProperties": {
208
+ "^\\w[-\\w_]*$": {
209
+ "properties": {
210
+ "links": {
211
+ "$ref": "#/definitions/links"
212
+ },
213
+ "data": {
214
+ "description": "Member, whose value represents \"resource linkage\".",
215
+ "oneOf": [
216
+ {
217
+ "$ref": "#/definitions/relationshipToOne"
218
+ },
219
+ {
220
+ "$ref": "#/definitions/relationshipToMany"
221
+ }
222
+ ]
223
+ },
224
+ "meta": {
225
+ "$ref": "#/definitions/meta"
226
+ }
227
+ },
228
+ "additionalProperties": false
229
+ }
230
+ },
231
+ "additionalProperties": false
232
+ },
233
+ "relationshipToOne": {
234
+ "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.",
235
+ "anyOf": [
236
+ {
237
+ "$ref": "#/definitions/empty"
238
+ },
239
+ {
240
+ "$ref": "#/definitions/linkage"
241
+ }
242
+ ]
243
+ },
244
+ "relationshipToMany": {
245
+ "description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
246
+ "type": "array",
247
+ "items": {
248
+ "$ref": "#/definitions/linkage"
249
+ },
250
+ "uniqueItems": true
251
+ },
252
+ "empty": {
253
+ "description": "Describes an empty to-one relationship.",
254
+ "type": "null"
255
+ },
256
+ "linkage": {
257
+ "description": "The \"type\" and \"id\" to non-empty members.",
258
+ "type": "object",
259
+ "required": [
260
+ "type",
261
+ "id"
262
+ ],
263
+ "properties": {
264
+ "type": {
265
+ "type": "string"
266
+ },
267
+ "id": {
268
+ "type": "string"
269
+ },
270
+ "meta": {
271
+ "$ref": "#/definitions/meta"
272
+ }
273
+ },
274
+ "additionalProperties": false
275
+ },
276
+ "pagination": {
277
+ "type": "object",
278
+ "properties": {
279
+ "first": {
280
+ "description": "The first page of data",
281
+ "oneOf": [
282
+ { "type": "string", "format": "uri" },
283
+ { "type": "null" }
284
+ ]
285
+ },
286
+ "last": {
287
+ "description": "The last page of data",
288
+ "oneOf": [
289
+ { "type": "string", "format": "uri" },
290
+ { "type": "null" }
291
+ ]
292
+ },
293
+ "prev": {
294
+ "description": "The previous page of data",
295
+ "oneOf": [
296
+ { "type": "string", "format": "uri" },
297
+ { "type": "null" }
298
+ ]
299
+ },
300
+ "next": {
301
+ "description": "The next page of data",
302
+ "oneOf": [
303
+ { "type": "string", "format": "uri" },
304
+ { "type": "null" }
305
+ ]
306
+ }
307
+ }
308
+ },
309
+
310
+ "jsonapi": {
311
+ "description": "An object describing the server's implementation",
312
+ "type": "object",
313
+ "properties": {
314
+ "version": {
315
+ "type": "string"
316
+ },
317
+ "meta": {
318
+ "$ref": "#/definitions/meta"
319
+ }
320
+ },
321
+ "additionalProperties": false
322
+ },
323
+
324
+ "error": {
325
+ "type": "object",
326
+ "properties": {
327
+ "id": {
328
+ "description": "A unique identifier for this particular occurrence of the problem.",
329
+ "type": "string"
330
+ },
331
+ "links": {
332
+ "$ref": "#/definitions/links"
333
+ },
334
+ "status": {
335
+ "description": "The HTTP status code applicable to this problem, expressed as a string value.",
336
+ "type": "string"
337
+ },
338
+ "code": {
339
+ "description": "An application-specific error code, expressed as a string value.",
340
+ "type": "string"
341
+ },
342
+ "title": {
343
+ "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.",
344
+ "type": "string"
345
+ },
346
+ "detail": {
347
+ "description": "A human-readable explanation specific to this occurrence of the problem.",
348
+ "type": "string"
349
+ },
350
+ "source": {
351
+ "type": "object",
352
+ "properties": {
353
+ "pointer": {
354
+ "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].",
355
+ "type": "string"
356
+ },
357
+ "parameter": {
358
+ "description": "A string indicating which query parameter caused the error.",
359
+ "type": "string"
360
+ }
361
+ }
362
+ },
363
+ "meta": {
364
+ "$ref": "#/definitions/meta"
365
+ }
366
+ },
367
+ "additionalProperties": false
368
+ }
369
+ }
370
+ }
@@ -1,24 +1,46 @@
1
1
  {
2
2
  "links": {
3
- "posts.author": {
4
- "link": "http://example.com/people/{posts.author}"
5
- }
3
+ "self": "http://example.com/articles",
4
+ "next": "http://example.com/articles?page[offset]=2",
5
+ "last": "http://example.com/articles?page[offset]=10"
6
6
  },
7
- "posts": [{
8
- "title": "Rails is Omakase",
9
- "links": {
10
- "comments": [ "1", "2", "3" ]
11
- }}, {
12
- "id": "3",
13
- "title": "Dependency Injection is Not a Virtue",
7
+ "data": [{
8
+ "type": "articles",
9
+ "attributes": {
10
+ "title": "JSON API paints my bikeshed!"
11
+ },
12
+ "relationships": {
13
+ "author": {
14
+ "links": {
15
+ "self": "http://example.com/articles/1/relationships/author",
16
+ "related": "http://example.com/articles/1/author"
17
+ },
18
+ "data": { "type": "people", "id": "9" }
19
+ },
20
+ "comments": {
21
+ "links": {
22
+ "self": "http://example.com/articles/1/relationships/comments",
23
+ "related": "http://example.com/articles/1/comments"
24
+ },
25
+ "data": [
26
+ { "type": "comments", "id": "5" },
27
+ { "type": "comments", "id": "12" }
28
+ ]
29
+ }
30
+ },
14
31
  "links": {
15
- "author": "9",
16
- "comments": "6"
32
+ "self": "http://example.com/articles/1"
17
33
  }
18
34
  }],
19
- "linked": {
20
- "people": [{
21
- "name": "@d2h"
22
- }]
23
- }
35
+ "included": [{
36
+ "type": "people",
37
+ "attributes": {
38
+ "first-name": "Dan",
39
+ "last-name": "Gebhardt",
40
+ "twitter": "dgeb"
41
+ },
42
+ "links": {
43
+ "self": "http://example.com/people/9"
44
+ }
45
+ }]
24
46
  }
@@ -1,57 +1,76 @@
1
1
  {
2
2
  "links": {
3
- "posts.author": {
4
- "href": "http://example.com/people/{posts.author}",
5
- "type": "people"
6
- },
7
- "posts.comments": {
8
- "href": "http://example.com/comments/{posts.comments}",
9
- "type": "comments"
10
- }
3
+ "self": "http://example.com/articles",
4
+ "next": "http://example.com/articles?page[offset]=2",
5
+ "last": "http://example.com/articles?page[offset]=10"
11
6
  },
12
- "posts": [{
7
+ "data": [{
8
+ "type": "articles",
13
9
  "id": "1",
14
- "title": "Rails is Omakase",
10
+ "attributes": {
11
+ "title": "JSON API paints my bikeshed!"
12
+ },
13
+ "relationships": {
14
+ "author": {
15
+ "links": {
16
+ "self": "http://example.com/articles/1/relationships/author",
17
+ "related": "http://example.com/articles/1/author"
18
+ },
19
+ "data": { "type": "people", "id": "9" }
20
+ },
21
+ "comments": {
22
+ "links": {
23
+ "self": "http://example.com/articles/1/relationships/comments",
24
+ "related": "http://example.com/articles/1/comments"
25
+ },
26
+ "data": [
27
+ { "type": "comments", "id": "5" },
28
+ { "type": "comments", "id": "12" }
29
+ ]
30
+ }
31
+ },
15
32
  "links": {
16
- "author": "9",
17
- "comments": [ "1", "2", "3" ]
18
- }}, {
19
- "id": "2",
20
- "title": "The Parley Letter",
33
+ "self": "http://example.com/articles/1"
34
+ }
35
+ }],
36
+ "included": [{
37
+ "type": "people",
38
+ "id": "9",
39
+ "attributes": {
40
+ "first-name": "Dan",
41
+ "last-name": "Gebhardt",
42
+ "twitter": "dgeb"
43
+ },
21
44
  "links": {
22
- "author": "9",
23
- "comments": [ "4", "5" ]
24
- }}, {
25
- "id": "3",
26
- "title": "Dependency Injection is Not a Virtue",
45
+ "self": "http://example.com/people/9"
46
+ }
47
+ }, {
48
+ "type": "comments",
49
+ "id": "5",
50
+ "attributes": {
51
+ "body": "First!"
52
+ },
53
+ "relationships": {
54
+ "author": {
55
+ "data": { "type": "people", "id": "2" }
56
+ }
57
+ },
27
58
  "links": {
28
- "author": "9",
29
- "comments": [ "6" ]
59
+ "self": "http://example.com/comments/5"
30
60
  }
31
- }],
32
- "linked": {
33
- "people": [{
34
- "id": "9",
35
- "name": "@d2h"
36
- }],
37
- "comments": [{
38
- "id": "1",
39
- "body": "Mmmmmakase"
40
- }, {
41
- "id": "2",
42
- "body": "I prefer unagi"
43
- }, {
44
- "id": "3",
45
- "body": "What's Omakase?"
46
- }, {
47
- "id": "4",
48
- "body": "Parley is a discussion, especially one between enemies"
49
- }, {
50
- "id": "5",
51
- "body": "The parsley letter"
52
- }, {
53
- "id": "6",
54
- "body": "Dependency Injection is Not a Vice"
55
- }]
56
- }
61
+ }, {
62
+ "type": "comments",
63
+ "id": "12",
64
+ "attributes": {
65
+ "body": "I like XML better"
66
+ },
67
+ "relationships": {
68
+ "author": {
69
+ "data": { "type": "people", "id": "9" }
70
+ }
71
+ },
72
+ "links": {
73
+ "self": "http://example.com/comments/12"
74
+ }
75
+ }]
57
76
  }
@@ -7,7 +7,7 @@ describe JSON::API::Conformant do
7
7
 
8
8
  subject { JSON::API::Conformant }
9
9
 
10
- describe ".validate" do
10
+ describe ".valid?" do
11
11
  context "when data is valid" do
12
12
  it "is true" do
13
13
  expect(subject.valid? valid_data).to be true
@@ -19,6 +19,18 @@ describe JSON::API::Conformant do
19
19
  expect(subject.valid? invalid_data).to be false
20
20
  end
21
21
  end
22
+
23
+ describe "version" do
24
+ it "defaults to draft" do
25
+ expect(subject).to receive(:schema).with("1.0").and_call_original
26
+ subject.validate({})
27
+ end
28
+
29
+ it "can be overridden" do
30
+ expect(subject).to receive(:schema).with("draft").and_call_original
31
+ subject.validate({}, version: "draft")
32
+ end
33
+ end
22
34
  end
23
35
 
24
36
  describe ".validate" do
@@ -30,11 +42,47 @@ describe JSON::API::Conformant do
30
42
 
31
43
  context "when data is invalid" do
32
44
  it "returns an array with the errors" do
33
- errors = [
34
- "The property '#/posts/0' did not contain a required property of 'id' in schema http://jsonapi.org/schema#",
35
- "The property '#/linked/people/0' did not contain a required property of 'id' in schema http://jsonapi.org/schema#"]
45
+ errors = [<<ERROR.chomp]
46
+ The property '#/' of type object did not match any of the required schemas. The schema specific errors were:
47
+
48
+ - oneOf #0:
49
+ - The property '#/included/0' did not contain a required property of 'id'
50
+ - The property '#/data' of type array did not match any of the required schemas. The schema specific errors were:
51
+
52
+ - oneOf #0:
53
+ - The property '#/data' of type array did not match the following type: object
54
+ - oneOf #1:
55
+ - The property '#/data/0' did not contain a required property of 'id'
56
+ - oneOf #2:
57
+ - The property '#/data' of type array did not match the following type: null
58
+ - oneOf #1:
59
+ - The property '#/' contains additional properties ["links", "data", "included"] outside of the schema when none are allowed
60
+ - The property '#/' did not contain a required property of 'errors'
61
+ - oneOf #2:
62
+ - The property '#/' contains additional properties ["data", "included"] outside of the schema when none are allowed
63
+ - The property '#/' did not contain a required property of 'meta'
64
+ ERROR
36
65
  expect(subject.validate invalid_data).to eq errors
37
66
  end
38
67
  end
68
+
69
+ describe "version" do
70
+ it "defaults to draft" do
71
+ expect(subject).to receive(:schema).with("1.0").and_call_original
72
+ subject.validate({})
73
+ end
74
+
75
+ it "can be overridden" do
76
+ expect(subject).to receive(:schema).with("draft").and_call_original
77
+ subject.validate({}, version: "draft")
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "#schema" do
83
+ it "allows version to be specified" do
84
+ expect(subject.send(:schema, "1.0")).to end_with "1.0.json"
85
+ expect(subject.send(:schema, "draft")).to end_with "draft.json"
86
+ end
39
87
  end
40
88
  end
@@ -27,9 +27,27 @@ RSpec.describe "be_json_api_conformant matcher" do
27
27
 
28
28
  it "returns the correct message when the test fails" do
29
29
  json = parse_fixture('invalid')
30
- expected_message = ["Expected data to be JSON API conformant:",
31
- "The property '#/posts/0' did not contain a required property of 'id' in schema http://jsonapi.org/schema#",
32
- "The property '#/linked/people/0' did not contain a required property of 'id' in schema http://jsonapi.org/schema#"]
30
+ expected_message = [<<-ERROR.chomp]
31
+ Expected data to be JSON API conformant:
32
+ * The property '#/' of type object did not match any of the required schemas. The schema specific errors were:
33
+
34
+ - oneOf #0:
35
+ - The property '#/included/0' did not contain a required property of 'id'
36
+ - The property '#/data' of type array did not match any of the required schemas. The schema specific errors were:
37
+
38
+ - oneOf #0:
39
+ - The property '#/data' of type array did not match the following type: object
40
+ - oneOf #1:
41
+ - The property '#/data/0' did not contain a required property of 'id'
42
+ - oneOf #2:
43
+ - The property '#/data' of type array did not match the following type: null
44
+ - oneOf #1:
45
+ - The property '#/' contains additional properties ["links", "data", "included"] outside of the schema when none are allowed
46
+ - The property '#/' did not contain a required property of 'errors'
47
+ - oneOf #2:
48
+ - The property '#/' contains additional properties ["data", "included"] outside of the schema when none are allowed
49
+ - The property '#/' did not contain a required property of 'meta'
50
+ ERROR
33
51
  begin
34
52
  expect(json).to be_json_api_conformant
35
53
  rescue RSpec::Expectations::ExpectationNotMetError => e
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_api_conformant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Sogamoso
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-11 00:00:00.000000000 Z
11
+ date: 2017-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '1.6'
20
- type: :development
18
+ version: '1.14'
19
+ name: bundler
21
20
  prerelease: false
21
+ type: :development
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: '1.14'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
32
+ version: '12.0'
33
+ name: rake
35
34
  prerelease: false
35
+ type: :development
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '12.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :runtime
46
+ version: '3.5'
47
+ name: rspec
49
48
  prerelease: false
49
+ type: :runtime
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '3.5'
55
55
  - !ruby/object:Gem::Dependency
56
- name: json-schema
57
56
  requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
58
  - - "~>"
60
59
  - !ruby/object:Gem::Version
61
- version: '2.2'
62
- type: :runtime
60
+ version: '2.8'
61
+ name: json-schema
63
62
  prerelease: false
63
+ type: :runtime
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.2'
68
+ version: '2.8'
69
69
  description: Interface for validating JSON objects against a JSON API schema.
70
70
  email:
71
71
  - sebasoga@gmail.com
@@ -74,7 +74,9 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".rspec"
77
78
  - ".travis.yml"
79
+ - CODE_OF_CONDUCT.md
78
80
  - Gemfile
79
81
  - LICENSE.txt
80
82
  - README.md
@@ -84,6 +86,7 @@ files:
84
86
  - lib/json_api_conformant/conformant.rb
85
87
  - lib/json_api_conformant/matchers/rspec.rb
86
88
  - lib/json_api_conformant/version.rb
89
+ - schemas/1.0.json
87
90
  - schemas/draft.json
88
91
  - spec/fixtures/invalid.json
89
92
  - spec/fixtures/valid.json
@@ -95,7 +98,7 @@ homepage: https://github.com/sebasoga/json_api_conformant
95
98
  licenses:
96
99
  - MIT
97
100
  metadata: {}
98
- post_install_message:
101
+ post_install_message:
99
102
  rdoc_options: []
100
103
  require_paths:
101
104
  - lib
@@ -110,9 +113,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
113
  - !ruby/object:Gem::Version
111
114
  version: '0'
112
115
  requirements: []
113
- rubyforge_project:
114
- rubygems_version: 2.2.2
115
- signing_key:
116
+ rubyforge_project:
117
+ rubygems_version: 2.6.8
118
+ signing_key:
116
119
  specification_version: 4
117
120
  summary: Ruby JSON API validator.
118
121
  test_files:
@@ -122,4 +125,3 @@ test_files:
122
125
  - spec/json_api_conformant/matchers/rspec_spec.rb
123
126
  - spec/spec_helper.rb
124
127
  - spec/support/json_parser.rb
125
- has_rdoc: