rspec-openapi 0.2.2 → 0.3.4
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 +4 -4
- data/.rspec +2 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +5 -1
- data/README.md +11 -6
- data/Rakefile +4 -2
- data/lib/rspec/openapi.rb +2 -1
- data/lib/rspec/openapi/hooks.rb +3 -2
- data/lib/rspec/openapi/record.rb +2 -2
- data/lib/rspec/openapi/record_builder.rb +53 -12
- data/lib/rspec/openapi/schema_builder.rb +16 -11
- data/lib/rspec/openapi/version.rb +1 -1
- data/rspec-openapi.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72b0193cdb3e3f8ee7b2cf52f1d2211a0b57a2074424323ab595af78693b5563
|
4
|
+
data.tar.gz: 021e6b386ffb4ed889bd08e61b8d26030cae32667fd8225f1e6ad24e1345aaf4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65e8998e2bcfd5ad2d34bd42477e86474baa3daadc8de07210ae9601c05cdb571306b9e8768d3d50de803fd078e167592febea3f820df294e3807e09f0c0c2fd
|
7
|
+
data.tar.gz: 1b9fee7f0277f71d4364ee7d39679749c941afcf3fd79df0180abf7510379b9d06e7f9ce24f0cb686f258204c205251f0d50b7211706f82e62f27f1ebc2ff0ce
|
data/.rspec
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
## v0.3.4
|
2
|
+
|
3
|
+
* Generate tags by controller names
|
4
|
+
[#10](https://github.com/k0kubun/rspec-openapi/issues/10)
|
5
|
+
|
6
|
+
## v0.3.3
|
7
|
+
|
8
|
+
* Avoid `JSON::ParserError` when a response body is no content
|
9
|
+
[#9](https://github.com/k0kubun/rspec-openapi/issues/9)
|
10
|
+
|
11
|
+
## v0.3.2
|
12
|
+
|
13
|
+
* Stop generating format as path parameters in Rails
|
14
|
+
[#8](https://github.com/k0kubun/rspec-openapi/issues/8)
|
15
|
+
|
16
|
+
## v0.3.1
|
17
|
+
|
18
|
+
* Add `RSpec::OpenAPI.description_builder` config to dynamically generate a description [experimental]
|
19
|
+
[#6](https://github.com/k0kubun/rspec-openapi/issues/6)
|
20
|
+
|
21
|
+
## v0.3.0
|
22
|
+
|
23
|
+
* Initial support of rack-test and non-Rails apps [#5](https://github.com/k0kubun/rspec-openapi/issues/5)
|
24
|
+
|
1
25
|
## v0.2.2
|
2
26
|
|
3
27
|
* Allow disabling `example` by `RSpec::OpenAPI.enable_example = false`
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -29,7 +29,7 @@ $ OPENAPI=1 rspec
|
|
29
29
|
|
30
30
|
### Example
|
31
31
|
|
32
|
-
Let's say you have [a request spec](./spec/requests/tables_spec.rb) like this:
|
32
|
+
Let's say you have [a request spec](./spec/requests/rails/tables_spec.rb) like this:
|
33
33
|
|
34
34
|
```rb
|
35
35
|
RSpec.describe 'Tables', type: :request do
|
@@ -55,7 +55,7 @@ If you run the spec with `OPENAPI=1`,
|
|
55
55
|
OPENAPI=1 rspec spec/requests/tables_spec.rb
|
56
56
|
```
|
57
57
|
|
58
|
-
It will generate [`doc/openapi.yaml` file](./spec/
|
58
|
+
It will generate [`doc/openapi.yaml` file](./spec/rails/doc/openapi.yaml) like:
|
59
59
|
|
60
60
|
```yml
|
61
61
|
openapi: 3.0.3
|
@@ -65,15 +65,19 @@ paths:
|
|
65
65
|
"/tables":
|
66
66
|
get:
|
67
67
|
summary: 'tables #index'
|
68
|
+
tags:
|
69
|
+
- tables
|
68
70
|
parameters:
|
69
71
|
- name: page
|
70
72
|
in: query
|
71
73
|
schema:
|
72
74
|
type: integer
|
75
|
+
example: 1
|
73
76
|
- name: per
|
74
77
|
in: query
|
75
78
|
schema:
|
76
79
|
type: integer
|
80
|
+
example: 10
|
77
81
|
responses:
|
78
82
|
'200':
|
79
83
|
description: returns a list of tables
|
@@ -93,7 +97,7 @@ paths:
|
|
93
97
|
|
94
98
|
and the schema file can be used as an input of [Swagger UI](https://github.com/swagger-api/swagger-ui) or [Redoc](https://github.com/Redocly/redoc).
|
95
99
|
|
96
|
-

|
97
101
|
|
98
102
|
|
99
103
|
### Configuration
|
@@ -114,6 +118,9 @@ RSpec::OpenAPI.comment = <<~EOS
|
|
114
118
|
When you write a spec in spec/requests, running the spec with `OPENAPI=1 rspec` will
|
115
119
|
update this file automatically. You can also manually edit this file.
|
116
120
|
EOS
|
121
|
+
|
122
|
+
# Generate a custom description, given an RSpec example
|
123
|
+
RSpec::OpenAPI.description_builder = -> (example) { example.description }
|
117
124
|
```
|
118
125
|
|
119
126
|
### How can I add information which can't be generated from RSpec?
|
@@ -145,11 +152,9 @@ Beta
|
|
145
152
|
|
146
153
|
Basic features are there, and some people are already using this.
|
147
154
|
|
148
|
-
### Current
|
155
|
+
### Current limitation
|
149
156
|
|
150
157
|
* Generating a JSON file is not supported yet
|
151
|
-
* This only works for RSpec request specs
|
152
|
-
* Only Rails is supported for looking up a request route
|
153
158
|
|
154
159
|
### Other missing features with notes
|
155
160
|
|
data/Rakefile
CHANGED
data/lib/rspec/openapi.rb
CHANGED
@@ -5,8 +5,9 @@ module RSpec::OpenAPI
|
|
5
5
|
@path = 'doc/openapi.yaml'
|
6
6
|
@comment = nil
|
7
7
|
@enable_example = true
|
8
|
+
@description_builder = -> (example) { example.description }
|
8
9
|
|
9
10
|
class << self
|
10
|
-
attr_accessor :path, :comment, :enable_example
|
11
|
+
attr_accessor :path, :comment, :enable_example, :description_builder
|
11
12
|
end
|
12
13
|
end
|
data/lib/rspec/openapi/hooks.rb
CHANGED
@@ -8,8 +8,9 @@ require 'rspec/openapi/schema_merger'
|
|
8
8
|
records = []
|
9
9
|
|
10
10
|
RSpec.configuration.after(:each) do |example|
|
11
|
-
if example.metadata[:type] == :request && example.metadata[:openapi] != false
|
12
|
-
|
11
|
+
if example.metadata[:type] == :request && example.metadata[:openapi] != false
|
12
|
+
record = RSpec::OpenAPI::RecordBuilder.build(self, example: example)
|
13
|
+
records << record if record
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
data/lib/rspec/openapi/record.rb
CHANGED
@@ -5,8 +5,8 @@ RSpec::OpenAPI::Record = Struct.new(
|
|
5
5
|
:query_params, # @param [Hash] - {:query=>"string"}
|
6
6
|
:request_params, # @param [Hash] - {:request=>"body"}
|
7
7
|
:request_content_type, # @param [String] - "application/json"
|
8
|
-
:
|
9
|
-
:
|
8
|
+
:summary, # @param [String] - "v1/statuses #show"
|
9
|
+
:tags, # @param [Array] - ["Status"]
|
10
10
|
:description, # @param [String] - "returns a status"
|
11
11
|
:status, # @param [Integer] - 200
|
12
12
|
:response_body, # @param [Object] - {"status" => "ok"}
|
@@ -1,41 +1,82 @@
|
|
1
|
+
require 'action_dispatch'
|
1
2
|
require 'rspec/openapi/record'
|
2
3
|
|
3
4
|
class << RSpec::OpenAPI::RecordBuilder = Object.new
|
4
5
|
# @param [RSpec::ExampleGroups::*] context
|
5
6
|
# @param [RSpec::Core::Example] example
|
6
|
-
# @return [RSpec::OpenAPI::Record]
|
7
|
+
# @return [RSpec::OpenAPI::Record,nil]
|
7
8
|
def build(context, example:)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
if rack_test?(context)
|
10
|
+
request = ActionDispatch::Request.new(context.last_request.env)
|
11
|
+
response = ActionDispatch::TestResponse.new(*context.last_response.to_a)
|
12
|
+
else
|
13
|
+
request = context.request
|
14
|
+
response = context.response
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generate `path` and `summary` in a framework-friendly manner when possible
|
18
|
+
if rails?
|
19
|
+
route = find_rails_route(request)
|
20
|
+
path = route.path.spec.to_s.delete_suffix('(.:format)')
|
21
|
+
summary = "#{route.requirements[:controller]} ##{route.requirements[:action]}"
|
22
|
+
tags = [route.requirements[:controller]]
|
23
|
+
else
|
24
|
+
path = request.path
|
25
|
+
summary = "#{request.method} #{request.path}"
|
26
|
+
end
|
27
|
+
|
28
|
+
response_body =
|
29
|
+
begin
|
30
|
+
response.parsed_body
|
31
|
+
rescue JSON::ParserError
|
32
|
+
nil
|
33
|
+
end
|
12
34
|
|
13
35
|
RSpec::OpenAPI::Record.new(
|
14
36
|
method: request.request_method,
|
15
|
-
path:
|
16
|
-
path_params: request
|
37
|
+
path: path,
|
38
|
+
path_params: raw_path_params(request),
|
17
39
|
query_params: request.query_parameters,
|
18
40
|
request_params: raw_request_params(request),
|
19
41
|
request_content_type: request.content_type,
|
20
|
-
|
21
|
-
|
22
|
-
description: example
|
42
|
+
summary: summary,
|
43
|
+
tags: tags,
|
44
|
+
description: RSpec::OpenAPI.description_builder.call(example),
|
23
45
|
status: response.status,
|
24
|
-
response_body:
|
46
|
+
response_body: response_body,
|
25
47
|
response_content_type: response.content_type,
|
26
48
|
).freeze
|
27
49
|
end
|
28
50
|
|
29
51
|
private
|
30
52
|
|
53
|
+
def rails?
|
54
|
+
defined?(Rails) && Rails.application
|
55
|
+
end
|
56
|
+
|
57
|
+
def rack_test?(context)
|
58
|
+
defined?(Rack::Test::Methods) && context.class < Rack::Test::Methods
|
59
|
+
end
|
60
|
+
|
31
61
|
# @param [ActionDispatch::Request] request
|
32
|
-
def
|
62
|
+
def find_rails_route(request)
|
33
63
|
Rails.application.routes.router.recognize(request) do |route|
|
34
64
|
return route
|
35
65
|
end
|
36
66
|
raise "No route matched for #{request.request_method} #{request.path_info}"
|
37
67
|
end
|
38
68
|
|
69
|
+
# :controller and :action always exist. :format is added when routes is configured as such.
|
70
|
+
def raw_path_params(request)
|
71
|
+
if rails?
|
72
|
+
request.path_parameters.reject do |key, _value|
|
73
|
+
%i[controller action format].include?(key)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
request.path_parameters
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
39
80
|
# workaround to get real request parameters
|
40
81
|
# because ActionController::ParamsWrapper overwrites request_parameters
|
41
82
|
def raw_request_params(request)
|
@@ -2,23 +2,29 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
|
|
2
2
|
# @param [RSpec::OpenAPI::Record] record
|
3
3
|
# @return [Hash]
|
4
4
|
def build(record)
|
5
|
+
response = {
|
6
|
+
description: record.description,
|
7
|
+
}
|
8
|
+
|
9
|
+
if record.response_body
|
10
|
+
response[:content] = {
|
11
|
+
normalize_content_type(record.response_content_type) => {
|
12
|
+
schema: build_property(record.response_body),
|
13
|
+
example: (record.response_body if example_enabled?),
|
14
|
+
}.compact,
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
5
18
|
{
|
6
19
|
paths: {
|
7
20
|
normalize_path(record.path) => {
|
8
21
|
record.method.downcase => {
|
9
|
-
summary:
|
22
|
+
summary: record.summary,
|
23
|
+
tags: record.tags,
|
10
24
|
parameters: build_parameters(record),
|
11
25
|
requestBody: build_request_body(record),
|
12
26
|
responses: {
|
13
|
-
record.status.to_s =>
|
14
|
-
description: record.description,
|
15
|
-
content: {
|
16
|
-
normalize_content_type(record.response_content_type) => {
|
17
|
-
schema: build_property(record.response_body),
|
18
|
-
example: (record.response_body if example_enabled?),
|
19
|
-
}.compact,
|
20
|
-
},
|
21
|
-
},
|
27
|
+
record.status.to_s => response,
|
22
28
|
},
|
23
29
|
}.compact,
|
24
30
|
},
|
@@ -36,7 +42,6 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
|
|
36
42
|
parameters = []
|
37
43
|
|
38
44
|
record.path_params.each do |key, value|
|
39
|
-
next if %i[controller action].include?(key)
|
40
45
|
parameters << {
|
41
46
|
name: key.to_s,
|
42
47
|
in: 'path',
|
data/rspec-openapi.gemspec
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-openapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takashi Kokubun
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: actionpack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rspec
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|