esplanade 1.2.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +33 -0
- data/.rubocop.yml +10 -3
- data/.ruby-version +1 -1
- data/.tool-versions +1 -0
- data/CHANGELOG.md +34 -3
- data/README.md +166 -38
- data/esplanade.gemspec +8 -8
- data/lib/esplanade/middlewares/check_custom_response_middleware.rb +3 -3
- data/lib/esplanade/request.rb +1 -6
- data/lib/esplanade/request/doc.rb +18 -6
- data/lib/esplanade/request/error.rb +93 -0
- data/lib/esplanade/request/raw.rb +8 -0
- data/lib/esplanade/request/raw/body.rb +14 -7
- data/lib/esplanade/request/validation.rb +37 -3
- data/lib/esplanade/response.rb +1 -5
- data/lib/esplanade/response/doc.rb +5 -1
- data/lib/esplanade/response/error.rb +82 -0
- data/lib/esplanade/response/raw/body.rb +5 -4
- data/lib/esplanade/response/validation.rb +3 -2
- data/lib/esplanade/version.rb +1 -1
- metadata +28 -46
- data/.travis.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f5a2030af1a5071793987d6ee1bab57942a83efd21ae68b6323de133c0667e4b
|
4
|
+
data.tar.gz: 2474417384e61677938e602e48657bb8acffaeed13cdbf1593c64c4d97620f42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
AllCops:
|
2
|
-
|
2
|
+
NewCops: enable
|
3
|
+
TargetRubyVersion: 2.4
|
3
4
|
|
4
|
-
|
5
|
-
|
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
|
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.7.1
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 2.7.1
|
data/CHANGELOG.md
CHANGED
@@ -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
|
-
*
|
45
|
+
* fixes
|
15
46
|
* add rewind rack.input
|
16
47
|
|
17
48
|
### 1.1.1 - 2018-02-13
|
18
49
|
|
19
|
-
*
|
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
|
-
*
|
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
|
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
|
13
|
-
|
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
|
-
|
43
|
+
After that execute:
|
24
44
|
|
25
|
-
|
45
|
+
```bash
|
46
|
+
$ bundle
|
47
|
+
```
|
26
48
|
|
27
|
-
Or install
|
49
|
+
Or install the gem by yourself:
|
28
50
|
|
29
|
-
|
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
|
-
##
|
63
|
+
## Middlewares
|
40
64
|
|
41
65
|
### Esplanade::SafeMiddleware
|
42
66
|
|
43
|
-
|
67
|
+
Debug logger.
|
44
68
|
|
45
69
|
### Esplanade::DangerousMiddleware
|
46
70
|
|
47
|
-
It throws errors, so you
|
71
|
+
It throws errors, so you should add your own middleware for processing.
|
48
72
|
|
49
73
|
```ruby
|
50
|
-
|
51
|
-
|
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
|
-
|
80
|
+
Use it if you want to be sure that you have documented new custom responses.
|
57
81
|
|
58
82
|
```ruby
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
90
|
+
Parent class for those described below.
|
67
91
|
|
68
92
|
### Esplanade::Request::Error
|
69
93
|
|
70
|
-
|
94
|
+
Parent class for those described below. Inherited from `Esplanade::Error`.
|
71
95
|
|
72
96
|
#### Esplanade::Request::PrefixNotMatch
|
73
97
|
|
74
|
-
Error message
|
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
|
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
|
-
|
137
|
+
Throws an error also when the body is empty and equal nil.
|
83
138
|
|
84
|
-
Error message
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
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)
|
data/esplanade.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
lib = File.expand_path('
|
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', '~>
|
22
|
-
spec.add_development_dependency '
|
23
|
-
spec.add_development_dependency '
|
24
|
-
spec.add_development_dependency '
|
25
|
-
spec.add_development_dependency '
|
26
|
-
spec.add_development_dependency '
|
27
|
-
spec.
|
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
|
-
|
10
|
-
|
11
|
-
|
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(
|
data/lib/esplanade/request.rb
CHANGED
@@ -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
|
11
|
-
|
12
|
-
|
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
|
17
|
-
@
|
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 ||=
|
21
|
-
{}
|
22
|
-
else
|
23
|
-
MultiJson.load(to_string)
|
24
|
-
end
|
21
|
+
@hash ||= MultiJson.load(to_string)
|
25
22
|
rescue MultiJson::ParseError
|
26
|
-
raise BodyIsNotJson
|
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
|
-
|
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
|
-
|
14
|
-
|
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
|
-
|
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
|
data/lib/esplanade/response.rb
CHANGED
@@ -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
|
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
|
-
@
|
15
|
-
@
|
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
|
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
|
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,
|
data/lib/esplanade/version.rb
CHANGED
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.
|
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:
|
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:
|
59
|
+
version: 3.0.0
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
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:
|
69
|
+
version: 3.0.0
|
70
70
|
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version:
|
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:
|
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:
|
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: '
|
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: '
|
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.
|
107
|
+
version: '3.9'
|
128
108
|
- - ">="
|
129
109
|
- !ruby/object:Gem::Version
|
130
|
-
version: 3.
|
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.
|
117
|
+
version: '3.9'
|
138
118
|
- - ">="
|
139
119
|
- !ruby/object:Gem::Version
|
140
|
-
version: 3.
|
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.
|
127
|
+
version: '0.81'
|
148
128
|
- - ">="
|
149
129
|
- !ruby/object:Gem::Version
|
150
|
-
version: 0.
|
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.
|
137
|
+
version: '0.81'
|
158
138
|
- - ">="
|
159
139
|
- !ruby/object:Gem::Version
|
160
|
-
version: 0.
|
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.
|
147
|
+
version: '0.18'
|
168
148
|
- - ">="
|
169
149
|
- !ruby/object:Gem::Version
|
170
|
-
version: 0.
|
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.
|
157
|
+
version: '0.18'
|
178
158
|
- - ">="
|
179
159
|
- !ruby/object:Gem::Version
|
180
|
-
version: 0.
|
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
|
-
- ".
|
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:
|
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
|
-
|
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
|
data/.travis.yml
DELETED