esplanade 1.2.0 → 1.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d56ac3bbfdcd35af5878ab7c38ba6192ef4e5957
4
- data.tar.gz: a17fd30d62e0039c6d70389e8f197e1b46a8bf17
2
+ SHA256:
3
+ metadata.gz: f5a2030af1a5071793987d6ee1bab57942a83efd21ae68b6323de133c0667e4b
4
+ data.tar.gz: 2474417384e61677938e602e48657bb8acffaeed13cdbf1593c64c4d97620f42
5
5
  SHA512:
6
- metadata.gz: fcbf87e4765ff6ac1b388e490c03dd9c72f57e062fdd9598e247ad4425e51f1723234142af8e0b89ff8611fe7e45834abbbb7c6c49e7237f23729cbe2b07209e
7
- data.tar.gz: 40d6f05bbc3ac4125d0e26f5ff21d0df8fd96fea36eb86efdb99547d3a16d1decb28feb8e93e86ee0cb0382bd21a1453d94cf77b0131e1974fae5ac1487be652
6
+ metadata.gz: 490ca6b622daf918b964966a523d751744923048a5ea78a7eaea7bb4fee5bd6d4623a8951d5255ba0fae49ac78eeba5bc00b6bff876f05c38d9cec88e706a170
7
+ data.tar.gz: b8bfb543326e2d7789d4a1842c96ae163e1a84ba6b3118ee95b57fe53451a308429dc103f7678b613f081d61e29df9668842e2ef8c9062dcdc139bdfa80a0c65
@@ -0,0 +1,33 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Set up Ruby
24
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
25
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
26
+ # uses: ruby/setup-ruby@v1
27
+ uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
28
+ with:
29
+ ruby-version: 2.6
30
+ - name: Install dependencies
31
+ run: bundle install
32
+ - name: Run tests
33
+ run: bundle exec rake
@@ -1,8 +1,9 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.2
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.4
3
4
 
4
- Metrics/LineLength:
5
- Max: 120
5
+ Layout/LineLength:
6
+ Enabled: false
6
7
 
7
8
  Style/Documentation:
8
9
  Enabled: false
@@ -13,6 +14,12 @@ Style/FrozenStringLiteralComment:
13
14
  Metrics/BlockLength:
14
15
  Enabled: false
15
16
 
17
+ Metrics/ParameterLists:
18
+ Enabled: false
19
+
20
+ Metrics/MethodLength:
21
+ Enabled: false
22
+
16
23
  Style/IfUnlessModifier:
17
24
  Enabled: false
18
25
 
@@ -1 +1 @@
1
- 2.2.0
1
+ 2.7.1
@@ -0,0 +1 @@
1
+ ruby 2.7.1
@@ -1,5 +1,36 @@
1
1
  # Change log
2
2
 
3
+ ### 1.6.0 - 2020-10-12
4
+
5
+ * features
6
+ * in the errors write not only a documented path but also a raw [#11](https://github.com/funbox/esplanade/issues/11)
7
+ * write in the documentation that the body is empty and nil is skipped [#13](https://github.com/funbox/esplanade/issues/13)
8
+ * redefine error PrefixNotMatch for response [#17](https://github.com/funbox/esplanade/issues/17)
9
+ * content-type can contain additional parameters [#21](https://github.com/funbox/esplanade/issues/21)
10
+ * update esplanade for the new tomograph [#29](https://github.com/funbox/esplanade/issues/29)
11
+
12
+ ### 1.5.0 - 2020-04-07
13
+
14
+ * improvements
15
+ * updated dependenses
16
+ * fixed warnings on ruby 2.7
17
+
18
+ ### 1.4.0 - 2019-08-19
19
+
20
+ * features
21
+ * add details for Esplanade::Response::Error
22
+
23
+ ### 1.3.0 - 2018-03-16
24
+
25
+ * features
26
+ * add Esplanade::Request::ContentTypeIsNotJson error
27
+ * add reduced version message about request body
28
+
29
+ ### 1.2.1 - 2018-02-20
30
+
31
+ * features
32
+ * more information about the invalid request
33
+
3
34
  ### 1.2.0 - 2018-02-15
4
35
 
5
36
  * features
@@ -11,12 +42,12 @@
11
42
 
12
43
  ### 1.1.2 - 2018-02-14
13
44
 
14
- * bug fixes
45
+ * fixes
15
46
  * add rewind rack.input
16
47
 
17
48
  ### 1.1.1 - 2018-02-13
18
49
 
19
- * bug fixes
50
+ * fixes
20
51
  * read body if Content-Type application/json
21
52
 
22
53
  ### 1.1.0 - 2017-10-18
@@ -26,5 +57,5 @@
26
57
 
27
58
  ### 1.0.1 - 2017-10-09
28
59
 
29
- * bug fixes
60
+ * fixes
30
61
  * allow request body to be nil
data/README.md CHANGED
@@ -1,16 +1,36 @@
1
1
  # Esplanade
2
2
 
3
- <a href="https://funbox.ru">
4
- <img src="https://funbox.ru/badges/sponsored_by_funbox.svg" alt="Sponsored by FunBox" width=250 />
5
- </a>
6
-
7
3
  [![Gem Version](https://badge.fury.io/rb/esplanade.svg)](https://badge.fury.io/rb/esplanade)
8
- [![Build Status](https://travis-ci.org/funbox/esplanade.svg?branch=master)](https://travis-ci.org/funbox/esplanade)
9
4
 
10
- This gem will help you validation and sinhronize your API in strict accordance to the documentation in
5
+ This gem helps you to validate and synchronize your API in strict accordance to the documentation in
11
6
  [API Blueprint](https://apiblueprint.org/) format.
12
- To do this it automatically searches received requestes and responses in the documentation and run validates
13
- json-schemas.
7
+ To do this it automatically searches received requests and responses in the documentation and run
8
+ JSON-schemas validators.
9
+
10
+ ## Contents
11
+
12
+ - [Installation](#installation)
13
+ - [Usage](#usage)
14
+ - [Middlewares](#middlewares)
15
+ - [Esplanade::SafeMiddleware](#esplanadesafemiddleware)
16
+ - [Esplanade::DangerousMiddleware](#esplanadedangerousmiddleware)
17
+ - [Esplanade::CheckCustomResponseMiddleware](#esplanadecheckcustomresponsemiddleware)
18
+ - [Esplanade::Error](#esplanadeerror)
19
+ - [Esplanade::Request::Error](#esplanaderequesterror)
20
+ - [Esplanade::Request::PrefixNotMatch](#esplanaderequestprefixnotmatch)
21
+ - [Esplanade::Request::NotDocumented](#esplanaderequestnotdocumented)
22
+ - [Esplanade::Request::ContentTypeIsNotJson](#esplanaderequestcontenttypeisnotjson)
23
+ - [Esplanade::Request::BodyIsNotJson](#esplanaderequestbodyisnotjson)
24
+ - [Esplanade::Request::Invalid](#esplanaderequestinvalid)
25
+ - [Esplanade::Response::Error](#esplanaderesponseerror)
26
+ - [Esplanade::Response::NotDocumented](#esplanaderesponsenotdocumented)
27
+ - [Esplanade::Response::BodyIsNotJson](#esplanaderesponsebodyisnotjson)
28
+ - [Esplanade::Response::Invalid](#esplanaderesponseinvalid)
29
+ - [Middleware args](#middleware-args)
30
+ - [`apib_path`](#apib_path)
31
+ - [`drafter_yaml_path`](#drafter_yaml_path)
32
+ - [`prefix`](#prefix)
33
+ - [License](#license)
14
34
 
15
35
  ## Installation
16
36
 
@@ -20,105 +40,213 @@ Add this line to your application's Gemfile:
20
40
  gem 'esplanade'
21
41
  ```
22
42
 
23
- And then execute:
43
+ After that execute:
24
44
 
25
- $ bundle
45
+ ```bash
46
+ $ bundle
47
+ ```
26
48
 
27
- Or install it yourself as:
49
+ Or install the gem by yourself:
28
50
 
29
- $ gem install esplanade
51
+ ```bash
52
+ $ gem install esplanade
53
+ ```
30
54
 
31
55
  ## Usage
32
56
 
33
- `config/application.rb`
57
+ `config/application.rb`:
34
58
 
35
59
  ```ruby
36
60
  config.middleware.use Esplanade::SafeMiddleware, apib_path: 'doc.apib'
37
61
  ```
38
62
 
39
- ## Middleware
63
+ ## Middlewares
40
64
 
41
65
  ### Esplanade::SafeMiddleware
42
66
 
43
- Only debug logger.
67
+ Debug logger.
44
68
 
45
69
  ### Esplanade::DangerousMiddleware
46
70
 
47
- It throws errors, so you will need to add your own middleware for processing.
71
+ It throws errors, so you should add your own middleware for processing.
48
72
 
49
73
  ```ruby
50
- config.middleware.use YourMiddleware
51
- config.middleware.use Esplanade::DangerousMiddleware, apib_path: 'doc.apib'
74
+ config.middleware.use YourMiddleware
75
+ config.middleware.use Esplanade::DangerousMiddleware, apib_path: 'doc.apib'
52
76
  ```
53
77
 
54
78
  ### Esplanade::CheckCustomResponseMiddleware
55
79
 
56
- If you want to be sure that you have documented new custom responses.
80
+ Use it if you want to be sure that you have documented new custom responses.
57
81
 
58
82
  ```ruby
59
- config.middleware.use Esplanade::CheckCustomResponseMiddleware, apib_path: 'doc.apib'
60
- config.middleware.use YourMiddleware
61
- config.middleware.use Esplanade::DangerousMiddleware, apib_path: 'doc.apib'
83
+ config.middleware.use Esplanade::CheckCustomResponseMiddleware, apib_path: 'doc.apib'
84
+ config.middleware.use YourMiddleware
85
+ config.middleware.use Esplanade::DangerousMiddleware, apib_path: 'doc.apib'
62
86
  ```
63
87
 
64
88
  ## Esplanade::Error
65
89
 
66
- From him the `Esplanade::Request::Error` and `Esplanade::Response::Error` are inherited.
90
+ Parent class for those described below.
67
91
 
68
92
  ### Esplanade::Request::Error
69
93
 
70
- From him the `Esplanade::Request::PrefixNotMatch`, `Esplanade::Request::NotDocumented`, `Esplanade::Request::BodyIsNotJson` and `Esplanade::Request::Invalid` are inherited.
94
+ Parent class for those described below. Inherited from `Esplanade::Error`.
71
95
 
72
96
  #### Esplanade::Request::PrefixNotMatch
73
97
 
74
- Error message: `{:method=>"method", :path=>"path"}`.
98
+ Error message format:
99
+
100
+ ```ruby
101
+ {
102
+ :method => "method",
103
+ :path => "path",
104
+ :raw_path => "path",
105
+ :content_type => "content_type"
106
+ }
107
+ ```
75
108
 
76
109
  #### Esplanade::Request::NotDocumented
77
110
 
78
- Error message: `{:method=>"method", :path=>"path"}`.
111
+ Error message format:
112
+
113
+ ```ruby
114
+ {
115
+ :method => "method",
116
+ :path => "path",
117
+ :raw_path => "path",
118
+ :content_type => "content_type"
119
+ }
120
+ ```
121
+
122
+ #### Esplanade::Request::ContentTypeIsNotJson
123
+
124
+ Error message format:
125
+
126
+ ```ruby
127
+ {
128
+ :method => "method",
129
+ :path => "path",
130
+ :raw_path => "path",
131
+ :content_type => "content_type"
132
+ }
133
+ ```
79
134
 
80
135
  #### Esplanade::Request::BodyIsNotJson
81
136
 
82
- Only if the documentation for this request indicates that `Content-Type: application/json`.
137
+ Throws an error also when the body is empty and equal nil.
83
138
 
84
- Error message: `{:method=>"method", :path=>"path", :body=>"{\"state\": 1"}`.
139
+ Error message format:
140
+
141
+ ```ruby
142
+ {
143
+ :method => "method",
144
+ :path => "path",
145
+ :raw_path => "path",
146
+ :content_type => "content_type",
147
+ :body => "body"
148
+ }
149
+ ```
85
150
 
86
151
  #### Esplanade::Request::Invalid
87
152
 
88
- Error message: `{:method=>"method", :path=>"path", :body=>"body", :error=>["error"]}`.
153
+ Error message format:
154
+
155
+ ```ruby
156
+ {
157
+ :method => "method",
158
+ :path => "path",
159
+ :raw_path => "path",
160
+ :content_type => "content_type",
161
+ :body => "body",
162
+ :error => ["error"]
163
+ }
164
+ ```
89
165
 
90
166
  ### Esplanade::Response::Error
91
167
 
92
- From him the `Esplanade::Response::NotDocumented`, `Esplanade::Response::BodyIsNotJson` and `Esplanade::Response::Invalid` are inherited.
168
+ Parent class for those described below. Inherited from `Esplanade::Error`.
169
+
170
+ #### Esplanade::Response::PrefixNotMatch
171
+
172
+ Error message format:
173
+
174
+ ```ruby
175
+ {
176
+ :request => {
177
+ :method => "method",
178
+ :path => "path"
179
+ },
180
+ :status => "status"
181
+ }
182
+ ```
93
183
 
94
184
  #### Esplanade::Response::NotDocumented
95
185
 
96
- Error message: `{:request=>{:method=>"method", :path=>"path"}, :status=>"status"}`.
186
+ Error message format:
187
+
188
+ ```ruby
189
+ {
190
+ :request => {
191
+ :method => "method",
192
+ :path => "path",
193
+ :raw_path => "path"
194
+ },
195
+ :status => "status"
196
+ }
197
+ ```
97
198
 
98
199
  #### Esplanade::Response::BodyIsNotJson
99
200
 
100
- Only if the documentation for all the responses of one request indicates that `Content-Type: application/json`.
201
+ It's thrown when expected response to request isn't JSON (not `Content-Type: application/json`) and there's no non-JSON responses documented for the endpoint.
202
+
203
+ Error message format:
101
204
 
102
- Error message: `{:request=>{:method=>"method", :path=>"path"}, :status=>"status", :body=>"body"}`.
205
+ ```ruby
206
+ {
207
+ :request => {
208
+ :method => "method",
209
+ :path => "path",
210
+ :raw_path => "path"
211
+ },
212
+ :status => "status",
213
+ :body => "body"
214
+ }
215
+ ```
103
216
 
104
217
  #### Esplanade::Response::Invalid
105
218
 
106
- Error message: `{:request=>{:method=>"method", :path=>"path"}, :status=>"status", :body=>"body", :error=>["error"]}`.
219
+ Error message format:
220
+
221
+ ```ruby
222
+ {
223
+ :request => {
224
+ :method => "method",
225
+ :path => "path",
226
+ :raw_path => "path"
227
+ },
228
+ :status => "status",
229
+ :body => "body",
230
+ :error => ["error"]
231
+ }
232
+ ```
107
233
 
108
234
  ## Middleware args
109
235
 
110
- ### apib_path
236
+ ### `apib_path`
111
237
 
112
238
  Path to API Blueprint documentation. There must be an installed [drafter](https://github.com/apiaryio/drafter) to parse it.
113
239
 
114
- ### drafter_yaml_path
240
+ ### `drafter_yaml_path`
115
241
 
116
242
  Path to API Blueprint documentation pre-parsed with `drafter` and saved to a YAML file.
117
243
 
118
- ### prefix
244
+ ### `prefix`
119
245
 
120
- Prefix of API requests. Example: `'/api'`. The prefix is added to the requests in the documentation.
246
+ Prefix for API requests. Example: `'/api'`. The prefix is added to the requests in the documentation.
121
247
 
122
248
  ## License
123
249
 
124
250
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
251
+
252
+ [![Sponsored by FunBox](https://funbox.ru/badges/sponsored_by_funbox_centered.svg)](https://funbox.ru)
@@ -1,4 +1,4 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'esplanade/version'
4
4
 
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.add_runtime_dependency 'json-schema', '~> 2.6', '>= 2.6.2'
20
20
  spec.add_runtime_dependency 'multi_json', '~> 1.11', '>= 1.11.1'
21
- spec.add_runtime_dependency 'tomograph', '~> 1.2', '>= 1.2.0'
22
- spec.add_development_dependency 'bundler', '~> 1.12'
23
- spec.add_development_dependency 'byebug', '~> 8.2', '>= 8.2.1'
24
- spec.add_development_dependency 'rake', '~> 10.0'
25
- spec.add_development_dependency 'rspec', '~> 3.4', '>= 3.4.0'
26
- spec.add_development_dependency 'rubocop', '~> 0.52', '>= 0.52.1'
27
- spec.add_development_dependency 'simplecov', '~> 0.11', '>= 0.11.2'
21
+ spec.add_runtime_dependency 'tomograph', '~> 3.0.0', '>= 3.0.0'
22
+ spec.add_development_dependency 'byebug', '>= 10.0.0'
23
+ spec.add_development_dependency 'rake', '~> 13'
24
+ spec.add_development_dependency 'rspec', '~> 3.9', '>= 3.9.0'
25
+ spec.add_development_dependency 'rubocop', '~> 0.81', '>= 0.81.0'
26
+ spec.add_development_dependency 'simplecov', '~> 0.18', '>= 0.18'
27
+ spec.required_ruby_version = '>= 2.4.0'
28
28
  end
@@ -6,9 +6,9 @@ module Esplanade
6
6
  class CheckCustomResponseMiddleware
7
7
  def initialize(
8
8
  app,
9
- prefix: Esplanade.configuration.prefix,
10
- apib_path: Esplanade.configuration.apib_path,
11
- drafter_yaml_path: Esplanade.configuration.drafter_yaml_path
9
+ prefix: Esplanade.configuration.prefix,
10
+ apib_path: Esplanade.configuration.apib_path,
11
+ drafter_yaml_path: Esplanade.configuration.drafter_yaml_path
12
12
  )
13
13
  @app = app
14
14
  @documentation = Tomograph::Tomogram.new(
@@ -1,15 +1,10 @@
1
1
  require 'esplanade/request/doc'
2
2
  require 'esplanade/request/raw'
3
3
  require 'esplanade/request/validation'
4
+ require 'esplanade/request/error'
4
5
 
5
6
  module Esplanade
6
7
  class Request
7
- class Error < Esplanade::Error; end
8
- class PrefixNotMatch < Error; end
9
- class NotDocumented < Error; end
10
- class BodyIsNotJson < Error; end
11
- class Invalid < Error; end
12
-
13
8
  def initialize(documentation, env)
14
9
  @documentation = documentation
15
10
  @env = env
@@ -7,14 +7,20 @@ module Esplanade
7
7
  end
8
8
 
9
9
  def tomogram
10
- raise PrefixNotMatch, message unless @main_documentation.prefix_match?(@raw.path)
11
- @tomogram = @main_documentation.find_request(method: @raw.method, path: @raw.path)
12
- raise NotDocumented, message if @tomogram.nil?
10
+ raise PrefixNotMatch.new(**message) unless @main_documentation.prefix_match?(@raw.path)
11
+
12
+ @tomogram = @main_documentation.find_request_with_content_type(
13
+ method: @raw.method,
14
+ path: @raw.path,
15
+ content_type: @raw.content_type
16
+ )
17
+ raise NotDocumented.new(**message) if @tomogram.nil?
18
+
13
19
  @tomogram
14
20
  end
15
21
 
16
- def json_schema
17
- @json_schema ||= tomogram.request
22
+ def json_schemas
23
+ @json_schemas ||= tomogram.requests
18
24
  end
19
25
 
20
26
  def method
@@ -25,6 +31,10 @@ module Esplanade
25
31
  @path ||= tomogram.path.to_s
26
32
  end
27
33
 
34
+ def content_type
35
+ @content_type ||= tomogram.content_type.to_s
36
+ end
37
+
28
38
  def responses
29
39
  @responses ||= tomogram.responses
30
40
  rescue NotDocumented
@@ -36,7 +46,9 @@ module Esplanade
36
46
  def message
37
47
  {
38
48
  method: @raw.method,
39
- path: @raw.path
49
+ path: @raw.path,
50
+ raw_path: @raw.raw_path,
51
+ content_type: @raw.content_type
40
52
  }
41
53
  end
42
54
  end
@@ -0,0 +1,93 @@
1
+ module Esplanade
2
+ class Request
3
+ class Error < Esplanade::Error; end
4
+
5
+ class PrefixNotMatch < Error; end
6
+
7
+ class NotDocumented < Error
8
+ def initialize(method:, path:, raw_path:, content_type:)
9
+ @method = method
10
+ @path = path
11
+ @raw_path = raw_path
12
+ @content_type = content_type
13
+
14
+ super(to_hash)
15
+ end
16
+
17
+ def to_hash
18
+ {
19
+ method: @method,
20
+ path: @path,
21
+ raw_path: @raw_path,
22
+ content_type: @content_type
23
+ }
24
+ end
25
+ end
26
+
27
+ class ContentTypeIsNotJson < Error
28
+ def initialize(method:, path:, raw_path:, content_type:)
29
+ @method = method
30
+ @raw_path = raw_path
31
+ @path = path
32
+ @content_type = content_type
33
+
34
+ super(to_hash)
35
+ end
36
+
37
+ def to_hash
38
+ {
39
+ method: @method,
40
+ path: @path,
41
+ raw_path: @raw_path,
42
+ content_type: @content_type
43
+ }
44
+ end
45
+ end
46
+
47
+ class BodyIsNotJson < Error
48
+ def initialize(method:, path:, raw_path:, content_type:, body:)
49
+ @method = method
50
+ @path = path
51
+ @raw_path = raw_path
52
+ @content_type = content_type
53
+ @body = body
54
+
55
+ super(to_hash)
56
+ end
57
+
58
+ def to_hash
59
+ {
60
+ method: @method,
61
+ path: @path,
62
+ raw_path: @raw_path,
63
+ content_type: @content_type,
64
+ body: @body
65
+ }
66
+ end
67
+ end
68
+
69
+ class Invalid < Error
70
+ def initialize(method:, path:, raw_path:, content_type:, body:, error:)
71
+ @method = method
72
+ @path = path
73
+ @raw_path = raw_path
74
+ @content_type = content_type
75
+ @body = body
76
+ @error = error
77
+
78
+ super(to_hash)
79
+ end
80
+
81
+ def to_hash
82
+ {
83
+ method: @method,
84
+ path: @path,
85
+ raw_path: @raw_path,
86
+ content_type: @content_type,
87
+ body: @body,
88
+ error: @error
89
+ }
90
+ end
91
+ end
92
+ end
93
+ end
@@ -15,9 +15,17 @@ module Esplanade
15
15
  @path ||= @env['PATH_INFO']
16
16
  end
17
17
 
18
+ def raw_path
19
+ @raw_path ||= "#{@env['PATH_INFO']}/#{@env['QUERY_STRING']}"
20
+ end
21
+
18
22
  def body
19
23
  @body ||= Body.new(self, @env)
20
24
  end
25
+
26
+ def content_type
27
+ @content_type ||= @env['CONTENT_TYPE'].to_s.split(';').first
28
+ end
21
29
  end
22
30
  end
23
31
  end
@@ -11,19 +11,24 @@ module Esplanade
11
11
 
12
12
  def to_string
13
13
  return @string if @string
14
+
14
15
  @string = @env['rack.input'].read
15
16
  @env['rack.input'].rewind
16
17
  @string
17
18
  end
18
19
 
19
20
  def to_hash
20
- @hash ||= if to_string.nil?
21
- {}
22
- else
23
- MultiJson.load(to_string)
24
- end
21
+ @hash ||= MultiJson.load(to_string)
25
22
  rescue MultiJson::ParseError
26
- raise BodyIsNotJson, message
23
+ raise BodyIsNotJson.new(**message)
24
+ end
25
+
26
+ def reduced_version
27
+ @reduced_version ||= if to_string && to_string.size >= 1000
28
+ "#{to_string[0..499]}...#{to_string[500..-1]}"
29
+ else
30
+ to_string
31
+ end
27
32
  end
28
33
 
29
34
  private
@@ -32,7 +37,9 @@ module Esplanade
32
37
  {
33
38
  method: @raw_request.method,
34
39
  path: @raw_request.path,
35
- body: to_string
40
+ raw_path: @raw_request.raw_path,
41
+ content_type: @raw_request.content_type,
42
+ body: reduced_version
36
43
  }
37
44
  end
38
45
  end
@@ -10,17 +10,51 @@ module Esplanade
10
10
  end
11
11
 
12
12
  def valid!
13
- @error ||= JSON::Validator.fully_validate(@doc.json_schema, @raw.body.to_hash)
14
- raise Invalid, message if @error != []
13
+ raise ContentTypeIsNotJson.new(**mini_message) unless @doc.content_type == 'application/json'
14
+
15
+ @error ||= if @doc.json_schemas.size == 1
16
+ one_json_schema
17
+ else
18
+ more_than_one_json_schema
19
+ end
20
+
21
+ raise Invalid.new(**message) unless @error.empty?
15
22
  end
16
23
 
17
24
  private
18
25
 
26
+ def one_json_schema
27
+ JSON::Validator.fully_validate(@doc.json_schemas.first, @raw.body.to_hash)
28
+ end
29
+
30
+ def more_than_one_json_schema
31
+ main_res = @doc.json_schemas.each do |json_schema|
32
+ res = JSON::Validator.fully_validate(json_schema, @raw.body.to_hash)
33
+ break res if res == []
34
+ end
35
+ if main_res != []
36
+ ['invalid']
37
+ else
38
+ []
39
+ end
40
+ end
41
+
42
+ def mini_message
43
+ {
44
+ method: @doc.method,
45
+ path: @doc.path,
46
+ raw_path: @raw.raw_path,
47
+ content_type: @doc.content_type
48
+ }
49
+ end
50
+
19
51
  def message
20
52
  {
21
53
  method: @raw.method,
22
54
  path: @raw.path,
23
- body: @raw.body.to_string,
55
+ raw_path: @raw.raw_path,
56
+ content_type: @raw.content_type,
57
+ body: @raw.body.to_hash,
24
58
  error: @error
25
59
  }
26
60
  end
@@ -1,14 +1,10 @@
1
1
  require 'esplanade/response/doc'
2
2
  require 'esplanade/response/raw'
3
3
  require 'esplanade/response/validation'
4
+ require 'esplanade/response/error'
4
5
 
5
6
  module Esplanade
6
7
  class Response
7
- class Error < Esplanade::Error; end
8
- class NotDocumented < Error; end
9
- class BodyIsNotJson < Error; end
10
- class Invalid < Error; end
11
-
12
8
  attr_reader :request
13
9
 
14
10
  def initialize(request, status, raw_body)
@@ -8,8 +8,11 @@ module Esplanade
8
8
 
9
9
  def tomogram
10
10
  @tomogram ||= @request.doc.responses.find_all { |response| response['status'] == @raw.status }
11
- raise NotDocumented, message if @tomogram == []
11
+ raise NotDocumented.new(**message) if @tomogram == []
12
+
12
13
  @tomogram
14
+ rescue Esplanade::Request::PrefixNotMatch
15
+ raise PrefixNotMatch.new(**message)
13
16
  end
14
17
 
15
18
  def json_schemas
@@ -26,6 +29,7 @@ module Esplanade
26
29
  {
27
30
  request: {
28
31
  method: @request.raw.method,
32
+ raw_path: @request.raw.raw_path,
29
33
  path: @request.raw.path
30
34
  },
31
35
  status: @raw.status
@@ -0,0 +1,82 @@
1
+ module Esplanade
2
+ class Response
3
+ class Error < Esplanade::Error; end
4
+
5
+ class PrefixNotMatch < Error; end
6
+
7
+ class NotDocumented < Error
8
+ def initialize(request:, status:)
9
+ @method = request[:method]
10
+ @path = request[:path]
11
+ @raw_path = request[:raw_path]
12
+ @status = status
13
+
14
+ super(to_hash)
15
+ end
16
+
17
+ def to_hash
18
+ {
19
+ request:
20
+ {
21
+ method: @method,
22
+ path: @path,
23
+ raw_path: @raw_path
24
+ },
25
+ status: @status
26
+ }
27
+ end
28
+ end
29
+
30
+ class BodyIsNotJson < Error
31
+ def initialize(request:, status:, body:)
32
+ @method = request[:method]
33
+ @path = request[:path]
34
+ @raw_path = request[:raw_path]
35
+ @status = status
36
+ @body = body
37
+
38
+ super(to_hash)
39
+ end
40
+
41
+ def to_hash
42
+ {
43
+ request:
44
+ {
45
+ method: @method,
46
+ path: @path,
47
+ raw_path: @raw_path
48
+ },
49
+ status: @status,
50
+ body: @body
51
+ }
52
+ end
53
+ end
54
+
55
+ class Invalid < Error
56
+ def initialize(request:, status:, body:, error:)
57
+ @method = request[:method]
58
+ @path = request[:path]
59
+ @raw_path = request[:raw_path]
60
+ @status = status
61
+ @body = body
62
+ @error = error
63
+
64
+ super(to_hash)
65
+ end
66
+
67
+ def to_hash
68
+ {
69
+ request:
70
+ {
71
+ method: @method,
72
+ path: @path,
73
+ raw_path: @raw_path
74
+ },
75
+ status: @status,
76
+ body: @body,
77
+ error: @error
78
+ }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -11,14 +11,14 @@ module Esplanade
11
11
  end
12
12
 
13
13
  def to_string
14
- @string ||= @raw_body.body rescue nil
15
- @string ||= @raw_body.first rescue nil
14
+ @to_string ||= @raw_body.body rescue nil
15
+ @to_string ||= @raw_body.first rescue nil
16
16
  end
17
17
 
18
18
  def to_hash
19
19
  @hash ||= MultiJson.load(to_string)
20
20
  rescue MultiJson::ParseError
21
- raise BodyIsNotJson, message
21
+ raise BodyIsNotJson.new(**message)
22
22
  end
23
23
 
24
24
  private
@@ -27,7 +27,8 @@ module Esplanade
27
27
  {
28
28
  request: {
29
29
  method: @request.raw.method,
30
- path: @request.raw.path
30
+ path: @request.raw.path,
31
+ raw_path: @request.raw.raw_path
31
32
  },
32
33
  status: @raw_response.status,
33
34
  body: @raw_response.body.to_string
@@ -15,7 +15,7 @@ module Esplanade
15
15
  else
16
16
  more_than_one_json_schema
17
17
  end
18
- raise Invalid, message if @error != []
18
+ raise Invalid.new(**message) if @error != []
19
19
  end
20
20
 
21
21
  private
@@ -40,7 +40,8 @@ module Esplanade
40
40
  {
41
41
  request: {
42
42
  method: @request.raw.method,
43
- path: @request.raw.path
43
+ path: @request.raw.path,
44
+ raw_path: @request.raw.raw_path
44
45
  },
45
46
  status: @raw.status,
46
47
  body: @raw.body.to_string,
@@ -1,3 +1,3 @@
1
1
  module Esplanade
2
- VERSION = '1.2.0'.freeze
2
+ VERSION = '1.6.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: esplanade
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - d.efimov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-15 00:00:00.000000000 Z
11
+ date: 2020-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json-schema
@@ -56,128 +56,108 @@ dependencies:
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '1.2'
59
+ version: 3.0.0
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 1.2.0
62
+ version: 3.0.0
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '1.2'
69
+ version: 3.0.0
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
- version: 1.2.0
73
- - !ruby/object:Gem::Dependency
74
- name: bundler
75
- requirement: !ruby/object:Gem::Requirement
76
- requirements:
77
- - - "~>"
78
- - !ruby/object:Gem::Version
79
- version: '1.12'
80
- type: :development
81
- prerelease: false
82
- version_requirements: !ruby/object:Gem::Requirement
83
- requirements:
84
- - - "~>"
85
- - !ruby/object:Gem::Version
86
- version: '1.12'
72
+ version: 3.0.0
87
73
  - !ruby/object:Gem::Dependency
88
74
  name: byebug
89
75
  requirement: !ruby/object:Gem::Requirement
90
76
  requirements:
91
- - - "~>"
92
- - !ruby/object:Gem::Version
93
- version: '8.2'
94
77
  - - ">="
95
78
  - !ruby/object:Gem::Version
96
- version: 8.2.1
79
+ version: 10.0.0
97
80
  type: :development
98
81
  prerelease: false
99
82
  version_requirements: !ruby/object:Gem::Requirement
100
83
  requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '8.2'
104
84
  - - ">="
105
85
  - !ruby/object:Gem::Version
106
- version: 8.2.1
86
+ version: 10.0.0
107
87
  - !ruby/object:Gem::Dependency
108
88
  name: rake
109
89
  requirement: !ruby/object:Gem::Requirement
110
90
  requirements:
111
91
  - - "~>"
112
92
  - !ruby/object:Gem::Version
113
- version: '10.0'
93
+ version: '13'
114
94
  type: :development
115
95
  prerelease: false
116
96
  version_requirements: !ruby/object:Gem::Requirement
117
97
  requirements:
118
98
  - - "~>"
119
99
  - !ruby/object:Gem::Version
120
- version: '10.0'
100
+ version: '13'
121
101
  - !ruby/object:Gem::Dependency
122
102
  name: rspec
123
103
  requirement: !ruby/object:Gem::Requirement
124
104
  requirements:
125
105
  - - "~>"
126
106
  - !ruby/object:Gem::Version
127
- version: '3.4'
107
+ version: '3.9'
128
108
  - - ">="
129
109
  - !ruby/object:Gem::Version
130
- version: 3.4.0
110
+ version: 3.9.0
131
111
  type: :development
132
112
  prerelease: false
133
113
  version_requirements: !ruby/object:Gem::Requirement
134
114
  requirements:
135
115
  - - "~>"
136
116
  - !ruby/object:Gem::Version
137
- version: '3.4'
117
+ version: '3.9'
138
118
  - - ">="
139
119
  - !ruby/object:Gem::Version
140
- version: 3.4.0
120
+ version: 3.9.0
141
121
  - !ruby/object:Gem::Dependency
142
122
  name: rubocop
143
123
  requirement: !ruby/object:Gem::Requirement
144
124
  requirements:
145
125
  - - "~>"
146
126
  - !ruby/object:Gem::Version
147
- version: '0.52'
127
+ version: '0.81'
148
128
  - - ">="
149
129
  - !ruby/object:Gem::Version
150
- version: 0.52.1
130
+ version: 0.81.0
151
131
  type: :development
152
132
  prerelease: false
153
133
  version_requirements: !ruby/object:Gem::Requirement
154
134
  requirements:
155
135
  - - "~>"
156
136
  - !ruby/object:Gem::Version
157
- version: '0.52'
137
+ version: '0.81'
158
138
  - - ">="
159
139
  - !ruby/object:Gem::Version
160
- version: 0.52.1
140
+ version: 0.81.0
161
141
  - !ruby/object:Gem::Dependency
162
142
  name: simplecov
163
143
  requirement: !ruby/object:Gem::Requirement
164
144
  requirements:
165
145
  - - "~>"
166
146
  - !ruby/object:Gem::Version
167
- version: '0.11'
147
+ version: '0.18'
168
148
  - - ">="
169
149
  - !ruby/object:Gem::Version
170
- version: 0.11.2
150
+ version: '0.18'
171
151
  type: :development
172
152
  prerelease: false
173
153
  version_requirements: !ruby/object:Gem::Requirement
174
154
  requirements:
175
155
  - - "~>"
176
156
  - !ruby/object:Gem::Version
177
- version: '0.11'
157
+ version: '0.18'
178
158
  - - ">="
179
159
  - !ruby/object:Gem::Version
180
- version: 0.11.2
160
+ version: '0.18'
181
161
  description:
182
162
  email:
183
163
  - d.efimov@fun-box.ru
@@ -185,10 +165,11 @@ executables: []
185
165
  extensions: []
186
166
  extra_rdoc_files: []
187
167
  files:
168
+ - ".github/workflows/ruby.yml"
188
169
  - ".gitignore"
189
170
  - ".rubocop.yml"
190
171
  - ".ruby-version"
191
- - ".travis.yml"
172
+ - ".tool-versions"
192
173
  - CHANGELOG.md
193
174
  - CODE_OF_CONDUCT.md
194
175
  - Gemfile
@@ -207,11 +188,13 @@ files:
207
188
  - lib/esplanade/middlewares/safe_middleware.rb
208
189
  - lib/esplanade/request.rb
209
190
  - lib/esplanade/request/doc.rb
191
+ - lib/esplanade/request/error.rb
210
192
  - lib/esplanade/request/raw.rb
211
193
  - lib/esplanade/request/raw/body.rb
212
194
  - lib/esplanade/request/validation.rb
213
195
  - lib/esplanade/response.rb
214
196
  - lib/esplanade/response/doc.rb
197
+ - lib/esplanade/response/error.rb
215
198
  - lib/esplanade/response/raw.rb
216
199
  - lib/esplanade/response/raw/body.rb
217
200
  - lib/esplanade/response/validation.rb
@@ -228,15 +211,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
228
211
  requirements:
229
212
  - - ">="
230
213
  - !ruby/object:Gem::Version
231
- version: '0'
214
+ version: 2.4.0
232
215
  required_rubygems_version: !ruby/object:Gem::Requirement
233
216
  requirements:
234
217
  - - ">="
235
218
  - !ruby/object:Gem::Version
236
219
  version: '0'
237
220
  requirements: []
238
- rubyforge_project:
239
- rubygems_version: 2.4.5
221
+ rubygems_version: 3.1.2
240
222
  signing_key:
241
223
  specification_version: 4
242
224
  summary: Validate requests and responses against API Blueprint specifications
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.2
4
- before_install: gem install bundler -v 1.12