rack-schema 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rack-schema.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Kyle Hargraves
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.
@@ -0,0 +1,102 @@
1
+ # Rack::Schema
2
+
3
+ Validate your application's responses against [JSON Schemas][json-schema].
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rack-schema'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rack-schema
18
+
19
+ ## Usage
20
+ Mount `Rack::Schema` as middleware in one of the normal manners:
21
+
22
+ ~~~~ruby
23
+ # using config.ru:
24
+ use Rack::Schema
25
+ run MyApp
26
+
27
+ # or application.rb:
28
+ config.middleware.use Rack::Schema
29
+ ~~~~
30
+
31
+ Your application can now return an HTTP [Link header][link-header]
32
+ with a `rel` attribute value of `describedby`, and `Rack::Schema` will
33
+ automatically attempt to validate responses against the specified
34
+ schema (using the [json-schema gem][hoxworth]). An example `Link`
35
+ header:
36
+
37
+ Link: <http://example.com/schemas/response>; rel="describedby"
38
+
39
+ If your schema applies only to a part of the JSON response, you can
40
+ use the `anchor` attribute to specify a JSON path to the relevant value:
41
+
42
+ Link: <http://example.com/schemas/widget>; rel="describedby"; anchor="#/widget"
43
+
44
+ This is actually a mis-use of the `anchor` attribute, which would
45
+ typically be used to specify an anchor within the *linked* document,
46
+ rather than the document being described. JSON schemas already support
47
+ the use of the hash fragment on its URI, however, so I've
48
+ re-appropriated it. Suggestions for a more compliant tactic are
49
+ welcome.
50
+
51
+ If your response is actually a collection of objects that should all
52
+ validate against the same schema, use the `collection` attribute:
53
+
54
+ # Assert that the response is an array, and each object within it is a valid widget.
55
+ Link: <http://example.com/schemas/widget>; rel="describedby"; collection="collection"
56
+
57
+ # Assert that the object at '#/widgets' is an array, and each object within it is a valid widget.
58
+ Link: <http://example.com/schemas/widget>; rel="describedby"; anchor="#/widgets"; collection="collection"
59
+
60
+ If the `Link` header contains multiple applicable links, they will
61
+ all be used to validate the response:
62
+
63
+ # Assert that '#/teams' is an array of valid teams, and '#/score' is a valid score.
64
+ Link: <http://example.com/schemas/team>; rel="describedby"; anchor="#/teams"; collection="collection",
65
+ <http://example.com/schemas/score>; rel="describedby"; anchor="#/score"
66
+
67
+ ## Configuration
68
+ By default, `rack-schema` will also instruct the validator to validate
69
+ your schema itself *as* a schema. To disable that behavior:
70
+
71
+ ~~~~ruby
72
+ use Rack::Schema, validate_schemas: false
73
+ ~~~~
74
+
75
+ If you are running the `rack-schema` response validator in a
76
+ production environment -- which you probably *shouldn't* be doing --
77
+ you don't want to actually expose the `describedby` link header
78
+ entries to the world, you can tell `rack-schema` to remove them from
79
+ the responses after using them:
80
+
81
+ ~~~~ruby
82
+ use Rack::Schema, swallow_links: true
83
+ ~~~~
84
+
85
+ With `swallow_links` on, only the *describedby* links will be removed;
86
+ your pagination or similar links will not be disturbed.
87
+
88
+
89
+ ## Potential Features?
90
+
91
+ 1. Validate incoming JSON bodies, but I just don't need that right now.
92
+ And it's unclear how we'd determine what schemas to use, or what we'd
93
+ do with the errors.
94
+
95
+ ## See Also
96
+
97
+ 1. [HTTP Link Header][link-header]
98
+ 2. [json-schema gem][hoxworth]
99
+
100
+ [json-schema]: http://json-schema.org
101
+ [link-header]: http://tools.ietf.org/html/rfc5988#section-5
102
+ [hoxworth]: https://github.com/hoxworth/json-schema
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ desc "Run the test suite"
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,83 @@
1
+ require "rack/schema/version"
2
+ require "json-schema"
3
+ require "link_header"
4
+ require "multi_json"
5
+
6
+ module Rack
7
+ class Schema
8
+ ValidationError = Class.new(StandardError)
9
+
10
+ def initialize(app, options = {}, &handler)
11
+ @app = app
12
+
13
+ @handler = handler
14
+ @handler ||= proc { |errors, env, (status, headers, body)|
15
+ json = ''
16
+ body.each { |s| json.concat s }
17
+ raise ValidationError.new({ errors: errors, body: json }) if errors.any?
18
+ }
19
+
20
+ @options = {
21
+ validate_schemas: true,
22
+ swallow_links: false
23
+ }.merge(options)
24
+ end
25
+
26
+ def call(env)
27
+ status, headers, body = @app.call(env)
28
+
29
+ link_header = LinkHeader.parse(headers['Link'])
30
+ schema_links = link_header.links.select do |link|
31
+ link.attrs['rel'] == 'describedby'
32
+ end
33
+
34
+ errors = validate(body, schema_links)
35
+ swallow(headers, link_header) if swallow_links?
36
+ response = [status, headers, body]
37
+ @handler.call(errors, env, response) || response
38
+ end
39
+
40
+ private
41
+
42
+ def validate(body, schema_links)
43
+ schema_links.each_with_object [] do |link, acc|
44
+ json = at_anchor(body, link.attrs['anchor'])
45
+
46
+ errs = JSON::Validator.fully_validate link.href, json, {
47
+ validate_schemas: @options[:validate_schemas],
48
+ list: link.attrs.key?('collection')
49
+ }
50
+
51
+ acc.push [link.to_s, errs] if errs.any?
52
+ end
53
+ end
54
+
55
+ def swallow_links?
56
+ @options[:swallow_links] == true
57
+ end
58
+
59
+ def swallow(headers, link_header)
60
+ link_header.links.reject! { |link| link.attrs['rel'] == 'describedby' }
61
+ if link_header.links.any?
62
+ headers['Link'] = link_header.to_s
63
+ else
64
+ headers.delete 'Link'
65
+ end
66
+ end
67
+
68
+ def at_anchor(body, anchor)
69
+ flat = ''
70
+ body.each { |s| flat.concat s }
71
+
72
+ return flat if anchor.nil? || anchor == '#' || anchor == '#/'
73
+
74
+ fragments = anchor.sub(/\A#\//, '').split('/')
75
+ fragments.reduce MultiJson.load(flat) do |value, fragment|
76
+ case value
77
+ when Hash then value.fetch(fragment, nil)
78
+ when Array then value.fetch(fragment.to_i, nil)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class Schema
3
+ VERSION = "0.5.0"
4
+ end
5
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rack/schema/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rack-schema"
8
+ spec.version = Rack::Schema::VERSION
9
+ spec.authors = ["Kyle Hargraves"]
10
+ spec.email = ["pd@krh.me"]
11
+ spec.description = %q{Validate rack responses against schema named in the Link header}
12
+ spec.summary = %q{Allows you to strictly validate each of your application's API responses against a declared JSON schema.}
13
+ spec.homepage = "http://github.com/pd/rack-schema"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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_dependency "rack"
22
+ spec.add_dependency "multi_json"
23
+ spec.add_dependency "json-schema"
24
+ spec.add_dependency "link_header"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.3"
27
+ spec.add_development_dependency "oj"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "rack-test"
30
+ spec.add_development_dependency "rspec"
31
+ spec.add_development_dependency "simplecov"
32
+ spec.add_development_dependency "pry"
33
+ end
@@ -0,0 +1,231 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::Schema, 'URIs, anchors, collections oh my!' do
4
+ Invalid = Class.new(StandardError)
5
+
6
+ def app
7
+ Rack::Builder.new do
8
+ use Rack::Schema do |errors, env, (status, headers, body)|
9
+ raise Invalid if errors.any?
10
+ headers['X-Schema'] = 'valid'
11
+ [status, headers, body]
12
+ end
13
+
14
+ run SpecHelpers::EchoApp
15
+ end
16
+ end
17
+
18
+ def assert_valid!
19
+ expect(last_response.headers['X-Schema']).to eq('valid')
20
+ end
21
+
22
+ def expect_invalid(&block)
23
+ expect(&block).to raise_error(Invalid)
24
+ end
25
+
26
+ context 'invalid JSON body' do
27
+ specify 'ignored without Link header' do
28
+ echo headers, '!!!'
29
+ assert_valid!
30
+
31
+ echo headers, nil
32
+ assert_valid!
33
+ end
34
+
35
+ specify 'with Link header present, we might have to parse the body' do
36
+ headers['Link'] = described_by schema_uri('object')
37
+ expect_invalid { echo headers, '!!!' }
38
+ expect_invalid { echo headers, nil }
39
+ end
40
+ end
41
+
42
+ context 'validate entire body' do
43
+ before do
44
+ headers['Link'] = described_by schema_uri('object')
45
+ end
46
+
47
+ specify 'pass' do
48
+ echo headers, {}
49
+ assert_valid!
50
+ end
51
+
52
+ specify 'fail by type' do
53
+ expect_invalid { echo headers, 'a string' }
54
+ expect_invalid { echo headers, [{}, {}] }
55
+ end
56
+ end
57
+
58
+ context 'validate at anchor' do
59
+ before do
60
+ headers['Link'] = described_by schema_uri('widget'), '#/widget'
61
+ end
62
+
63
+ specify 'pass at anchor' do
64
+ echo headers, { 'widget' => { 'name' => 'foo' } }
65
+ assert_valid!
66
+ end
67
+
68
+ specify 'fail; object was at root instead of anchor' do
69
+ expect_invalid do
70
+ echo headers, { 'name' => 'foo' }
71
+ end
72
+ end
73
+
74
+ specify 'fail; no such anchor' do
75
+ expect_invalid do
76
+ echo headers, { 'Widget' => { 'name' => 'foo' } }
77
+ end
78
+ end
79
+
80
+ specify 'fail; anchor pointed to collection' do
81
+ expect_invalid do
82
+ echo headers, { 'widget' => [{'name' => 'foo'}, {'name' => 'bar'}] }
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'validate at array element' do
88
+ before do
89
+ headers['Link'] = described_by schema_uri('widget'), '#/1'
90
+ end
91
+
92
+ specify 'pass' do
93
+ echo headers, ['anything', {'name' => 'real widget'}]
94
+ assert_valid!
95
+ end
96
+
97
+ specify 'fail; invalid' do
98
+ expect_invalid do
99
+ echo headers, ['anything', {'nope' => 'not okay'}]
100
+ end
101
+ end
102
+
103
+ specify 'fail; not an array' do
104
+ expect_invalid do
105
+ echo headers, {'some' => 'object'}
106
+ end
107
+ end
108
+
109
+ specify 'fail; wrong element' do
110
+ expect_invalid do
111
+ echo headers, [{'name' => 'widget'}, 'oops, backwards!']
112
+ end
113
+ end
114
+ end
115
+
116
+ ['#', '#/'].each do |anchor|
117
+ context "validate at anchor #{anchor.inspect}" do
118
+ before do
119
+ headers['Link'] = described_by schema_uri('widget'), anchor
120
+ end
121
+
122
+ specify 'pass' do
123
+ echo headers, { 'name' => 'foo' }
124
+ assert_valid!
125
+ end
126
+
127
+ specify 'fail' do
128
+ expect_invalid do
129
+ echo headers, { 'name' => true }
130
+ end
131
+
132
+ expect_invalid do
133
+ echo headers, { 'widget' => { 'name' => 'foo' } }
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ context 'validate collection' do
140
+ before do
141
+ headers['Link'] = described_by schema_uri('widget'), nil, :collection
142
+ end
143
+
144
+ specify 'pass' do
145
+ echo headers, [{'name' => 'foo'}, {'name' => 'bar'}]
146
+ assert_valid!
147
+ end
148
+
149
+ specify 'pass; empty array' do
150
+ echo headers, []
151
+ assert_valid!
152
+ end
153
+
154
+ specify 'fail; not an array' do
155
+ expect_invalid do
156
+ echo headers, {'name' => 'foo'}
157
+ end
158
+ end
159
+
160
+ specify 'fail; invalid entry' do
161
+ expect_invalid do
162
+ echo headers, [{'name' => 'foo'}, {'invalid' => true}]
163
+ end
164
+ end
165
+ end
166
+
167
+ context 'validate collection at anchor' do
168
+ before do
169
+ headers['Link'] = described_by schema_uri('widget'), '#/widgets', :collection
170
+ end
171
+
172
+ specify 'pass' do
173
+ echo headers, { 'widgets' => [{'name' => 'foo'}, {'name' => 'bar'}] }
174
+ assert_valid!
175
+ end
176
+
177
+ specify 'pass; empty array' do
178
+ echo headers, { 'widgets' => [] }
179
+ assert_valid!
180
+ end
181
+
182
+ specify 'fail; no such anchor' do
183
+ expect_invalid do
184
+ echo headers, { 'Widgets' => [{'name' => 'foo'}] }
185
+ end
186
+ end
187
+
188
+ specify 'fail; invalid entries' do
189
+ expect_invalid do
190
+ echo headers, { 'widgets' => [{'bogus' => 'object'}] }
191
+ end
192
+ end
193
+ end
194
+
195
+ context 'multiple schemas' do
196
+ before do
197
+ headers['Link'] = [described_by(schema_uri('response'), '#'),
198
+ described_by(schema_uri('widget'), '#/widgets', :collection),
199
+ described_by(schema_uri('auction'), '#/auction')].join(", ")
200
+ end
201
+
202
+ let(:body) do
203
+ { 'links' => [{'rel' => 'self'}],
204
+ 'widgets' => [{'name' => 'foo'}],
205
+ 'auction' => {'bids' => 10, 'price' => 100}
206
+ }
207
+ end
208
+
209
+ specify 'pass all' do
210
+ echo headers, body
211
+ assert_valid!
212
+ end
213
+
214
+ specify 'fail all' do
215
+ expect_invalid do
216
+ echo headers, {}
217
+ end
218
+
219
+ expect_invalid do
220
+ echo headers, {'links' => 'oops', 'widgets' => ['so', 'wrong'], 'auction' => nil}
221
+ end
222
+ end
223
+
224
+ specify 'fail one' do
225
+ body['links'] = []
226
+ expect_invalid do
227
+ echo headers, body
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::Schema do
4
+ context 'default handler' do
5
+ def app
6
+ Rack::Builder.new do
7
+ use Rack::Schema
8
+ run SpecHelpers::EchoApp
9
+ end
10
+ end
11
+
12
+ it 'raises Rack::Schema::ValidationError if there were errors' do
13
+ headers['Link'] = described_by schema_uri('widget')
14
+ expect {
15
+ echo headers, {}
16
+ }.to raise_error(Rack::Schema::ValidationError)
17
+ end
18
+
19
+ it 'otherwise does not alter the response' do
20
+ headers['Link'] = described_by schema_uri('widget')
21
+ echo headers, {'name' => 'foo'}
22
+
23
+ expect(last_response.headers).to have_key('Link')
24
+ expect(last_response.body).to eql(MultiJson.dump({'name' => 'foo'}))
25
+ end
26
+ end
27
+
28
+ context 'swallow_links: true' do
29
+ def app
30
+ Rack::Builder.new do
31
+ use Rack::Schema, swallow_links: true
32
+ run SpecHelpers::EchoApp
33
+ end
34
+ end
35
+
36
+ it 'removes only rel=describedby Links' do
37
+ headers['Link'] = [described_by(schema_uri('widget')),
38
+ '<http://another/link>; rel="next"'].join(", ")
39
+ echo headers, { 'name' => 'foo' }
40
+
41
+ expect(last_response.headers).to have_key('Link')
42
+ expect(last_response.headers['Link']).to eql('<http://another/link>; rel="next"')
43
+ end
44
+
45
+ it 'removes the Link header if empty' do
46
+ headers['Link'] = described_by schema_uri('widget')
47
+ echo headers, { 'name' => 'foo' }
48
+ expect(last_response.headers).not_to have_key('Link')
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-03/schema#",
3
+ "title": "An auction to sell a widget",
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "bids": { "type": "integer" },
7
+ "price": { "type": "integer", "required": true }
8
+ }
9
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-03/schema#",
3
+ "title": "Any ol' object",
4
+ "type": "object"
5
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-03/schema#",
3
+ "title": "Common schema for service JSON responses",
4
+
5
+ "properties": {
6
+ "links": {
7
+ "type": "array",
8
+ "items": {
9
+ "properties": { "rel": { "type": "string" } }
10
+ },
11
+ "minItems": 1
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-03/schema#",
3
+ "title": "A widget",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "properties": {
7
+ "name": { "type": "string", "required": true }
8
+ }
9
+ }
@@ -0,0 +1,59 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'rspec'
7
+ require 'rack/test'
8
+ require 'rack/schema'
9
+ require 'pry'
10
+
11
+ # `json' needs to be here because simplecov assumes that if
12
+ # ::JSON is defined, it means we have ruby's JSON loaded; otherwise,
13
+ # they use MultiJson. silly.
14
+ require "oj"
15
+ require "json"
16
+
17
+ module SpecHelpers
18
+ def echo(headers, body, status = 200)
19
+ env = {
20
+ 'echo.body' => MultiJson.dump(body),
21
+ 'echo.headers' => headers,
22
+ 'echo.status' => status
23
+ }
24
+ get '/', {}, env
25
+ end
26
+
27
+ def headers
28
+ @headers ||= {
29
+ 'Content-Type' => 'application/json'
30
+ }
31
+ end
32
+
33
+ def schema_uri(name)
34
+ "file://#{schema_file(name)}"
35
+ end
36
+
37
+ def schema_file(name)
38
+ File.expand_path("../schemas/#{name}.json", __FILE__)
39
+ end
40
+
41
+ def described_by(uri, anchor = nil, collection = nil)
42
+ header = "<#{uri}>; rel=\"describedby\""
43
+ header.concat "; anchor=\"#{anchor}\"" if anchor
44
+ header.concat "; collection=\"collection\"" if collection
45
+ header
46
+ end
47
+
48
+ module EchoApp
49
+ def self.call(env)
50
+ body = [env['echo.body']] # body should respond to :each
51
+ [env['echo.status'], env['echo.headers'], body]
52
+ end
53
+ end
54
+ end
55
+
56
+ RSpec.configure do |config|
57
+ config.include Rack::Test::Methods
58
+ config.include SpecHelpers
59
+ end
metadata ADDED
@@ -0,0 +1,246 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-schema
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kyle Hargraves
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: multi_json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: json-schema
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: link_header
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: bundler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.3'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.3'
94
+ - !ruby/object:Gem::Dependency
95
+ name: oj
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rake
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rack-test
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rspec
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: simplecov
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: pry
176
+ requirement: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ type: :development
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ description: Validate rack responses against schema named in the Link header
191
+ email:
192
+ - pd@krh.me
193
+ executables: []
194
+ extensions: []
195
+ extra_rdoc_files: []
196
+ files:
197
+ - .gitignore
198
+ - Gemfile
199
+ - LICENSE.txt
200
+ - README.md
201
+ - Rakefile
202
+ - lib/rack/schema.rb
203
+ - lib/rack/schema/version.rb
204
+ - rack-schema.gemspec
205
+ - spec/link_header_spec.rb
206
+ - spec/rack_schema_spec.rb
207
+ - spec/schemas/auction.json
208
+ - spec/schemas/object.json
209
+ - spec/schemas/response.json
210
+ - spec/schemas/widget.json
211
+ - spec/spec_helper.rb
212
+ homepage: http://github.com/pd/rack-schema
213
+ licenses:
214
+ - MIT
215
+ post_install_message:
216
+ rdoc_options: []
217
+ require_paths:
218
+ - lib
219
+ required_ruby_version: !ruby/object:Gem::Requirement
220
+ none: false
221
+ requirements:
222
+ - - ! '>='
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ required_rubygems_version: !ruby/object:Gem::Requirement
226
+ none: false
227
+ requirements:
228
+ - - ! '>='
229
+ - !ruby/object:Gem::Version
230
+ version: '0'
231
+ requirements: []
232
+ rubyforge_project:
233
+ rubygems_version: 1.8.23
234
+ signing_key:
235
+ specification_version: 3
236
+ summary: Allows you to strictly validate each of your application's API responses
237
+ against a declared JSON schema.
238
+ test_files:
239
+ - spec/link_header_spec.rb
240
+ - spec/rack_schema_spec.rb
241
+ - spec/schemas/auction.json
242
+ - spec/schemas/object.json
243
+ - spec/schemas/response.json
244
+ - spec/schemas/widget.json
245
+ - spec/spec_helper.rb
246
+ has_rdoc: