rack-spec 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +41 -3
- data/lib/rack/spec.rb +2 -0
- data/lib/rack/spec/error.rb +30 -0
- data/lib/rack/spec/error_handler.rb +19 -0
- data/lib/rack/spec/request_validation.rb +72 -7
- data/lib/rack/spec/version.rb +1 -1
- data/rack-spec.gemspec +1 -0
- data/spec/rack/spec/request_validation_spec.rb +25 -8
- data/spec/spec_helper.rb +2 -0
- metadata +17 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9d070ee1c712f33a4d50a9480bea910ff8674ba
|
4
|
+
data.tar.gz: 34ec8da54e93829dc3123145add042b246f79e46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 507ee6434b83a63a9a75899500f5778a34aa3854b0c68285ceda7bb63f97ad4a66880712f98d15269c3c07aab4bc54745fd0b3e7fcaa1b358da58764ddea43af
|
7
|
+
data.tar.gz: 0a6076dec2ca43cc4979790b6bfa92e557d119308e2e385f3b3d624079bf7736936b9c77d4f56d12c49c08cdf238c3cc4d3815e66378aee2f9acc2a00fa96312
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,49 @@
|
|
1
1
|
# Rack::Spec
|
2
2
|
Generate API server from [JSON Schema](http://json-schema.org/).
|
3
3
|
|
4
|
-
##
|
4
|
+
## Usage
|
5
|
+
```ruby
|
6
|
+
use Rack::Spec::ErrorHandler
|
7
|
+
use Rack::Spec::RequestValidation, schema: JSON.parse(File.read("schema.json")))
|
8
|
+
```
|
9
|
+
|
10
|
+
### Example
|
11
|
+
```sh
|
12
|
+
$ curl http://localhost:9292/recipes
|
13
|
+
{"id":"link_not_found","message":"Not found"}
|
14
|
+
|
15
|
+
$ curl http://localhost:9292/apps -H "Content-Type: application/json" -d "invalid-json"
|
16
|
+
{"id":"invalid_json","message":"Request body wasn't valid JSON"}
|
17
|
+
|
18
|
+
$ curl http://localhost:9292/apps -H "Content-Type: text/plain" -d "{}"
|
19
|
+
{"id":"invalid_content_type","message":"Invalid content type"}
|
20
|
+
|
21
|
+
$ curl http://localhost:9292/apps -H "Content-Type: application/json" -d '{"name":"x"}'
|
22
|
+
{"id":"invalid_parameter","message":"Invalid request.\n#/name: failed schema #/definitions/app/links/0/schema/properties/name: Expected string to match pattern \"/^[a-z][a-z0-9-]{3,50}$/\", value was: x."}
|
23
|
+
```
|
24
|
+
|
25
|
+
### Rack::Spec::RequestValidation
|
5
26
|
* Raise `Rack::Spec::RequestValidation::LinkNotFound` when given request is not defined in schema
|
6
27
|
* Raise `Rack::Spec::RequestValidation::InvalidContentType` for invalid content type
|
7
28
|
* Raise `Rack::Spec::RequestValidation::InvalidParameter` for invalid request parameter
|
8
29
|
|
9
|
-
|
10
|
-
|
30
|
+
### Rack::Spec::ErrorHandler
|
31
|
+
Returns appropriate error response including following properties when RequestValidation raises error.
|
32
|
+
|
33
|
+
* id: Error type identifier (e.g. `link_not_found`, `invalid_content_type`)
|
34
|
+
* message: Human readable message (e.g. `Not Found`, `Invalid Content-Type`)
|
35
|
+
|
36
|
+
### Errors
|
37
|
+
```
|
38
|
+
StandardError
|
39
|
+
|
|
40
|
+
Rack::Spec::Error
|
41
|
+
|
|
42
|
+
Rack::Spec::RequestValidation::Error
|
43
|
+
|
|
44
|
+
|--Rack::Spec::RequestValidation::LinkNotFound
|
45
|
+
|
|
46
|
+
|--Rack::Spec::RequestValidation::InvalidContentType
|
47
|
+
|
|
48
|
+
`--Rack::Spec::RequestValidation::InvalidParameter
|
11
49
|
```
|
data/lib/rack/spec.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Rack
|
2
|
+
module Spec
|
3
|
+
class Error < StandardError
|
4
|
+
# @return [Array] Rack response
|
5
|
+
def to_rack_response
|
6
|
+
[status, headers, [body]]
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# @note Override this
|
12
|
+
def status
|
13
|
+
500
|
14
|
+
end
|
15
|
+
|
16
|
+
# @note Override this
|
17
|
+
def id
|
18
|
+
"internal_server_error"
|
19
|
+
end
|
20
|
+
|
21
|
+
def headers
|
22
|
+
{ "Content-Type" => "application/json" }
|
23
|
+
end
|
24
|
+
|
25
|
+
def body
|
26
|
+
{ id: id, message: message }.to_json
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rack
|
2
|
+
module Spec
|
3
|
+
class ErrorHandler
|
4
|
+
# Behaves as a rack middleware
|
5
|
+
# @param app [Object] Rack application
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
# Behaves as a rack middleware
|
11
|
+
# @param env [Hash] Rack env
|
12
|
+
def call(env)
|
13
|
+
@app.call(env)
|
14
|
+
rescue Rack::Spec::Error => exception
|
15
|
+
exception.to_rack_response
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -38,21 +38,27 @@ module Rack
|
|
38
38
|
raise LinkNotFound
|
39
39
|
when has_body? && !has_valid_content_type?
|
40
40
|
raise InvalidContentType
|
41
|
-
when
|
42
|
-
raise
|
41
|
+
when has_body? && !has_valid_json?
|
42
|
+
raise InvalidJson
|
43
|
+
when has_body? && has_schema? && !has_valid_parameter?
|
44
|
+
raise InvalidParameter, "Invalid request.\n#{schema_validation_error_message}"
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
48
|
private
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
valid
|
50
|
+
def has_valid_json?
|
51
|
+
parameters
|
52
|
+
true
|
52
53
|
rescue MultiJson::ParseError
|
53
54
|
false
|
54
55
|
end
|
55
56
|
|
57
|
+
# @return [true, false] True if request parameters are all valid
|
58
|
+
def has_valid_parameter?
|
59
|
+
schema_validation_result[0]
|
60
|
+
end
|
61
|
+
|
56
62
|
# @return [true, false] True if any schema is defined for the current action
|
57
63
|
def has_schema?
|
58
64
|
!!link.schema
|
@@ -73,6 +79,21 @@ module Rack
|
|
73
79
|
!!link
|
74
80
|
end
|
75
81
|
|
82
|
+
# @return [Array] A result of schema validation for the current action
|
83
|
+
def schema_validation_result
|
84
|
+
@schema_validation_result ||= link.schema.validate(parameters)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Array] Errors of schema validation
|
88
|
+
def schema_validation_errors
|
89
|
+
schema_validation_result[1]
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [String] Joined error message to the result of schema validation
|
93
|
+
def schema_validation_error_message
|
94
|
+
JsonSchema::SchemaError.aggregate(schema_validation_errors).join("\n")
|
95
|
+
end
|
96
|
+
|
76
97
|
# @return [JsonSchema::Schema::Link, nil] Link for the current action
|
77
98
|
def link
|
78
99
|
if instance_variable_defined?(:@link)
|
@@ -134,19 +155,63 @@ module Rack
|
|
134
155
|
end
|
135
156
|
|
136
157
|
# Base error class for Rack::Spec::RequestValidation
|
137
|
-
class Error <
|
158
|
+
class Error < Error
|
138
159
|
end
|
139
160
|
|
140
161
|
# Error class for case when no link defined for given request
|
141
162
|
class LinkNotFound < Error
|
163
|
+
def initialize
|
164
|
+
super("Not found")
|
165
|
+
end
|
166
|
+
|
167
|
+
def status
|
168
|
+
404
|
169
|
+
end
|
170
|
+
|
171
|
+
def id
|
172
|
+
"link_not_found"
|
173
|
+
end
|
142
174
|
end
|
143
175
|
|
144
176
|
# Error class for invalid request content type
|
145
177
|
class InvalidContentType < Error
|
178
|
+
def initialize
|
179
|
+
super("Invalid content type")
|
180
|
+
end
|
181
|
+
|
182
|
+
def status
|
183
|
+
400
|
184
|
+
end
|
185
|
+
|
186
|
+
def id
|
187
|
+
"invalid_content_type"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Error class for invalid JSON
|
192
|
+
class InvalidJson < Error
|
193
|
+
def initialize
|
194
|
+
super("Request body wasn't valid JSON")
|
195
|
+
end
|
196
|
+
|
197
|
+
def status
|
198
|
+
400
|
199
|
+
end
|
200
|
+
|
201
|
+
def id
|
202
|
+
"invalid_json"
|
203
|
+
end
|
146
204
|
end
|
147
205
|
|
148
206
|
# Error class for invalid request parameter
|
149
207
|
class InvalidParameter < Error
|
208
|
+
def status
|
209
|
+
400
|
210
|
+
end
|
211
|
+
|
212
|
+
def id
|
213
|
+
"invalid_parameter"
|
214
|
+
end
|
150
215
|
end
|
151
216
|
end
|
152
217
|
end
|
data/lib/rack/spec/version.rb
CHANGED
data/rack-spec.gemspec
CHANGED
@@ -6,6 +6,7 @@ describe Rack::Spec::RequestValidation do
|
|
6
6
|
let(:app) do
|
7
7
|
data = schema
|
8
8
|
Rack::Builder.app do
|
9
|
+
use Rack::Spec::ErrorHandler
|
9
10
|
use Rack::Spec::RequestValidation, schema: data
|
10
11
|
run ->(env) do
|
11
12
|
[200, {}, ["OK"]]
|
@@ -75,8 +76,12 @@ describe Rack::Spec::RequestValidation do
|
|
75
76
|
"/undefined"
|
76
77
|
end
|
77
78
|
|
78
|
-
it "
|
79
|
-
|
79
|
+
it "returns link_not_found error" do
|
80
|
+
should == 404
|
81
|
+
response.body.should be_json_as(
|
82
|
+
id: "link_not_found",
|
83
|
+
message: "Not found",
|
84
|
+
)
|
80
85
|
end
|
81
86
|
end
|
82
87
|
|
@@ -85,8 +90,12 @@ describe Rack::Spec::RequestValidation do
|
|
85
90
|
env["CONTENT_TYPE"] = "text/plain"
|
86
91
|
end
|
87
92
|
|
88
|
-
it "
|
89
|
-
|
93
|
+
it "returns invalid_content_type error" do
|
94
|
+
should == 400
|
95
|
+
response.body.should be_json_as(
|
96
|
+
id: "invalid_content_type",
|
97
|
+
message: "Invalid content type",
|
98
|
+
)
|
90
99
|
end
|
91
100
|
end
|
92
101
|
|
@@ -99,8 +108,12 @@ describe Rack::Spec::RequestValidation do
|
|
99
108
|
{ name: "ab" }.to_json
|
100
109
|
end
|
101
110
|
|
102
|
-
it "
|
103
|
-
|
111
|
+
it "returns invalid_parameter error" do
|
112
|
+
should == 400
|
113
|
+
response.body.should be_json_as(
|
114
|
+
id: "invalid_parameter",
|
115
|
+
message: %r<\AInvalid request\.\n#/name: failed schema .+: Expected string to match pattern>,
|
116
|
+
)
|
104
117
|
end
|
105
118
|
end
|
106
119
|
|
@@ -109,8 +122,12 @@ describe Rack::Spec::RequestValidation do
|
|
109
122
|
"malformed"
|
110
123
|
end
|
111
124
|
|
112
|
-
it "
|
113
|
-
|
125
|
+
it "returns invalid_parameter error" do
|
126
|
+
should == 400
|
127
|
+
response.body.should be_json_as(
|
128
|
+
id: "invalid_json",
|
129
|
+
message: "Request body wasn't valid JSON",
|
130
|
+
)
|
114
131
|
end
|
115
132
|
end
|
116
133
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require "rack/builder"
|
2
2
|
require "rack/spec"
|
3
3
|
require "rack/test"
|
4
|
+
require "rspec/json_matcher"
|
4
5
|
|
5
6
|
RSpec.configure do |config|
|
6
7
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
7
8
|
config.run_all_when_everything_filtered = true
|
8
9
|
config.filter_run :focus
|
10
|
+
config.include RSpec::JsonMatcher
|
9
11
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Nakamura
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec-json_matcher
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
description:
|
126
140
|
email:
|
127
141
|
- r7kamura@gmail.com
|
@@ -137,6 +151,8 @@ files:
|
|
137
151
|
- Rakefile
|
138
152
|
- lib/rack-spec.rb
|
139
153
|
- lib/rack/spec.rb
|
154
|
+
- lib/rack/spec/error.rb
|
155
|
+
- lib/rack/spec/error_handler.rb
|
140
156
|
- lib/rack/spec/request_validation.rb
|
141
157
|
- lib/rack/spec/schema.rb
|
142
158
|
- lib/rack/spec/version.rb
|