json_api_conformant 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 92291efde255c5c90b95e15c05e83bf78847cfaf
4
+ data.tar.gz: af194f8d29d1c213ed446298e78530ee65edfa6c
5
+ SHA512:
6
+ metadata.gz: a1ad1aea511b450f83e5b761b5dc2fb55a1f493e73fa9e3fbd9b3bb72875214b6287e49d782462a77a18bb027cf05c485ce26f723597a9519ef82064378d5f49
7
+ data.tar.gz: 50d9dbc0363d0f0619b619fa8bc210ccfb69463c3ce759e0f75e61d739de5bf00f259c630453afc4f7c6af891f89e70daf940f2950b9a90eaa42b827f1b56f02
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in json_api_conformant.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sebastian Sogamoso
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # JSON API Conformant
2
+
3
+ When building an API in JSON it is important to follow conventions for the so
4
+ that your system clients know how to send a request for the available resources
5
+ to be fetched or modified and how your system will respond to those requests.
6
+
7
+ JSON API Conformant provides a narrow interface for validating JSON objects
8
+ against a [JSON API](http://jsonapi.org/) conforming
9
+ [JSON API schema](http://jsonapi.org/schema) and provides a custom RSpec
10
+ matcher for use in your tests.
11
+
12
+ **Important:** JSON API is a work in progress. The base schema is not a perfect
13
+ document. The fact that a JSON document validates against this schema, it does
14
+ not necessarily mean it is a valid JSON API document. The schema is provided by
15
+ JSON API for a base level sanity check.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'json_api_conformant'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install json_api_conformant
32
+
33
+ ## Usage
34
+
35
+ Validate if your JSON object is JSON API conformant.
36
+ ```ruby
37
+ valid_schema = {"posts" => [{"id" => "1"}]}
38
+ invalid_schema = {"comments" => "Nice gem!"}
39
+
40
+ JSON::API::Conformant.valid?(valid_schema) # => true
41
+ JSON::API::Conformant.valid?(invalid_schema) # => false
42
+ ```
43
+
44
+ Get errors when your JSON object is JSON API not conformant.
45
+ ```ruby
46
+ valid_schema = {"posts" => [{"id" => "1"}]}
47
+ invalid_schema = {"comments" => "Nice gem!"}
48
+
49
+ JSON::API::Conformant.validate(valid_schema) # => []
50
+ JSON::API::Conformant.validate(invalid_schema) # => ["The property
51
+ '#/comments' of type String did not match the"]
52
+ ```
53
+
54
+ JSON API Conformant wraps [json-schema](https://github.com/hoxworth/json-schema,
55
+ so other options that validator accepts will work here too.
56
+
57
+ ### RSpec Matcher
58
+
59
+ It is pretty straighword to use.
60
+ ```ruby
61
+ it "..." do
62
+ data = {"posts" => [{"id" => "1"}]}
63
+
64
+ expect(data).to be_json_api_conformant
65
+ end
66
+ ```
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it ( https://github.com/[my-github-username]/json_api_conformant/fork )
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Run the test suite (`rake`)
73
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
74
+ 5. Push to the branch (`git push origin my-new-feature`)
75
+ 6. Create a new Pull Request
76
+
77
+ ## License
78
+
79
+ See [LICENSE](https://github.com/sebasoga/json_api_conformant/blob/master/LICENSE.txt)
80
+ for details.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+ task :default => :spec
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'json_api_conformant/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "json_api_conformant"
8
+ spec.version = JSON::API::Conformant::VERSION
9
+ spec.authors = ["Sebastian Sogamoso"]
10
+ spec.email = ["sebasoga@gmail.com"]
11
+ spec.summary = %q{Ruby JSON API validator.}
12
+ spec.description = %q{Interface for validating JSON objects against a JSON API schema.}
13
+ spec.homepage = "https://github.com/sebasoga/json_api_conformant"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
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"
25
+ end
@@ -0,0 +1,32 @@
1
+ require 'json-schema'
2
+
3
+ module JSON
4
+ module API
5
+ class Conformant
6
+ SCHEMA_VERSION = 'draft'
7
+
8
+ class << self
9
+ def valid?(data, options={})
10
+ validator.validate(schema, data, options)
11
+ end
12
+
13
+ def validate(data, options={})
14
+ validator.fully_validate(schema, data, options)
15
+ end
16
+
17
+ private
18
+
19
+ def validator
20
+ JSON::Validator
21
+ end
22
+
23
+ def schema
24
+ File.join(Pathname.new(File.dirname(__FILE__)).parent.parent,
25
+ 'schemas',
26
+ "#{SCHEMA_VERSION}.json"
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ require 'rspec/expectations'
2
+ require 'json_api_conformant/conformant'
3
+
4
+ RSpec::Matchers.define :be_json_api_conformant do
5
+ match do |data|
6
+ json_api_conformant? data
7
+ end
8
+
9
+ failure_message do |data|
10
+ errors = get_errors_in data
11
+ message_for errors
12
+ end
13
+
14
+ failure_message_when_negated do |data|
15
+ "Expected data not to be JSON API conformant"
16
+ end
17
+
18
+ private
19
+
20
+ def json_api_conformant?(data)
21
+ JSON::API::Conformant.valid?(data)
22
+ end
23
+
24
+ def get_errors_in(data)
25
+ JSON::API::Conformant.validate(data)
26
+ end
27
+
28
+ def message_for(errors)
29
+ error_message = ['Expected data to be JSON API conformant:'] + errors
30
+ error_message.join("\n* ")
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module JSON
2
+ module API
3
+ class Conformant
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ require "json_api_conformant/version"
2
+ require "json_api_conformant/conformant"
3
+ require "json_api_conformant/matchers/rspec"
@@ -0,0 +1,40 @@
1
+ {
2
+ "id": "http://jsonapi.org/schema#",
3
+ "$schema": "http://json-schema.org/draft-04/schema#",
4
+ "title": "JSON API Schema",
5
+ "description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
6
+ "type": "object",
7
+ "resources":{
8
+ "type": "array",
9
+ "items": {
10
+ "type": "object",
11
+ "properties": {
12
+ "id": { "type":["string"] },
13
+ "href": { "type":"string" },
14
+ "links": { "type": "object" }
15
+ },
16
+ "required": ["id"]
17
+ }
18
+ },
19
+ "patternProperties": {
20
+ "^(?!href$)(?!links$)(?!id$)(?!meta)(?!linked)": {
21
+ "$ref":"#/resources"
22
+ }
23
+ },
24
+ "properties": {
25
+ "meta": {
26
+ "type": "object"
27
+ },
28
+ "links":{
29
+ "type": "object"
30
+ },
31
+ "linked": {
32
+ "type": "object",
33
+ "patternProperties": {
34
+ ".*": {
35
+ "$ref":"#/resources"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "links": {
3
+ "posts.author": {
4
+ "link": "http://example.com/people/{posts.author}"
5
+ }
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",
14
+ "links": {
15
+ "author": "9",
16
+ "comments": "6"
17
+ }
18
+ }],
19
+ "linked": {
20
+ "people": [{
21
+ "name": "@d2h"
22
+ }]
23
+ }
24
+ }
@@ -0,0 +1,57 @@
1
+ {
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
+ }
11
+ },
12
+ "posts": [{
13
+ "id": "1",
14
+ "title": "Rails is Omakase",
15
+ "links": {
16
+ "author": "9",
17
+ "comments": [ "1", "2", "3" ]
18
+ }}, {
19
+ "id": "2",
20
+ "title": "The Parley Letter",
21
+ "links": {
22
+ "author": "9",
23
+ "comments": [ "4", "5" ]
24
+ }}, {
25
+ "id": "3",
26
+ "title": "Dependency Injection is Not a Virtue",
27
+ "links": {
28
+ "author": "9",
29
+ "comments": [ "6" ]
30
+ }
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
+ }
57
+ }
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe JSON::API::Conformant do
4
+
5
+ let(:valid_data) { parse_fixture('valid') }
6
+ let(:invalid_data) { parse_fixture('invalid') }
7
+
8
+ subject { JSON::API::Conformant }
9
+
10
+ describe ".validate" do
11
+ context "when data is valid" do
12
+ it "is true" do
13
+ expect(subject.valid? valid_data).to be true
14
+ end
15
+ end
16
+
17
+ context "when data is invalid" do
18
+ it "is false" do
19
+ expect(subject.valid? invalid_data).to be false
20
+ end
21
+ end
22
+ end
23
+
24
+ describe ".validate" do
25
+ context "when data is valid" do
26
+ it "returns an empty array" do
27
+ expect(subject.validate valid_data).to eq []
28
+ end
29
+ end
30
+
31
+ context "when data is invalid" do
32
+ 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#"]
36
+ expect(subject.validate invalid_data).to eq errors
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "be_json_api_conformant matcher" do
4
+
5
+ context "when the JSON object is valid" do
6
+ it "is JSON API conformant" do
7
+ json = parse_fixture('valid')
8
+ expect(json).to be_json_api_conformant
9
+ end
10
+
11
+ it "returns the correct message when the test fails" do
12
+ json = parse_fixture('valid')
13
+ expected_message = 'Expected data not to be JSON API conformant'
14
+ begin
15
+ expect(json).not_to be_json_api_conformant
16
+ rescue RSpec::Expectations::ExpectationNotMetError => e
17
+ expect(e.to_s).to eq expected_message
18
+ end
19
+ end
20
+ end
21
+
22
+ context "when then JSON object is invalid" do
23
+ it "is not JSON API conformant" do
24
+ json = parse_fixture('invalid')
25
+ expect(json).not_to be_json_api_conformant
26
+ end
27
+
28
+ it "returns the correct message when the test fails" do
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#"]
33
+ begin
34
+ expect(json).to be_json_api_conformant
35
+ rescue RSpec::Expectations::ExpectationNotMetError => e
36
+ expect(e.to_s).to eq expected_message.join("\n* ")
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ ENV["env"] ||= "test"
2
+
3
+ require 'json_api_conformant'
4
+
5
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |file| require file }
6
+
7
+ RSpec.configure do |config|
8
+ config.include RSpecHelper
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'json'
2
+
3
+ module RSpecHelper
4
+ def parse_fixture(filename)
5
+ filepath = File.join(Pathname.new(File.dirname(__FILE__)).parent, 'fixtures', "#{filename}.json")
6
+ file = File.read(filepath)
7
+ JSON.parse(file)
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json_api_conformant
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Sogamoso
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json-schema
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.2'
69
+ description: Interface for validating JSON objects against a JSON API schema.
70
+ email:
71
+ - sebasoga@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - json_api_conformant.gemspec
82
+ - lib/json_api_conformant.rb
83
+ - lib/json_api_conformant/conformant.rb
84
+ - lib/json_api_conformant/matchers/rspec.rb
85
+ - lib/json_api_conformant/version.rb
86
+ - schemas/draft.json
87
+ - spec/fixtures/invalid.json
88
+ - spec/fixtures/valid.json
89
+ - spec/json_api_conformant/conformant_spec.rb
90
+ - spec/json_api_conformant/matchers/rspec_spec.rb
91
+ - spec/spec_helper.rb
92
+ - spec/support/json_parser.rb
93
+ homepage: https://github.com/sebasoga/json_api_conformant
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.2.2
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Ruby JSON API validator.
117
+ test_files:
118
+ - spec/fixtures/invalid.json
119
+ - spec/fixtures/valid.json
120
+ - spec/json_api_conformant/conformant_spec.rb
121
+ - spec/json_api_conformant/matchers/rspec_spec.rb
122
+ - spec/spec_helper.rb
123
+ - spec/support/json_parser.rb
124
+ has_rdoc: