oas_rails 0.3.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -0
- data/app/controllers/oas_rails/oas_rails_controller.rb +1 -1
- data/app/views/oas_rails/oas_rails/index.html.erb +1 -1
- data/lib/generators/oas_rails/config/templates/oas_rails_initializer.rb +11 -0
- data/lib/oas_rails/builders/content_builder.rb +55 -0
- data/lib/oas_rails/builders/operation_builder.rb +32 -0
- data/lib/oas_rails/builders/parameter_builder.rb +28 -0
- data/lib/oas_rails/builders/parameters_builder.rb +39 -0
- data/lib/oas_rails/builders/path_item_builder.rb +22 -0
- data/lib/oas_rails/builders/request_body_builder.rb +61 -0
- data/lib/oas_rails/builders/response_builder.rb +40 -0
- data/lib/oas_rails/builders/responses_builder.rb +58 -0
- data/lib/oas_rails/configuration.rb +17 -5
- data/lib/oas_rails/extractors/oas_route_extractor.rb +66 -0
- data/lib/oas_rails/extractors/render_response_extractor.rb +11 -36
- data/lib/oas_rails/oas_route.rb +0 -5
- data/lib/oas_rails/spec/components.rb +85 -0
- data/lib/oas_rails/spec/contact.rb +18 -0
- data/lib/oas_rails/spec/hashable.rb +39 -0
- data/lib/oas_rails/{info.rb → spec/info.rb} +30 -24
- data/lib/oas_rails/spec/license.rb +18 -0
- data/lib/oas_rails/spec/media_type.rb +84 -0
- data/lib/oas_rails/spec/operation.rb +25 -0
- data/lib/oas_rails/spec/parameter.rb +34 -0
- data/lib/oas_rails/spec/path_item.rb +33 -0
- data/lib/oas_rails/spec/paths.rb +26 -0
- data/lib/oas_rails/spec/reference.rb +16 -0
- data/lib/oas_rails/spec/request_body.rb +21 -0
- data/lib/oas_rails/spec/response.rb +20 -0
- data/lib/oas_rails/spec/responses.rb +25 -0
- data/lib/oas_rails/spec/server.rb +17 -0
- data/lib/oas_rails/spec/specable.rb +51 -0
- data/lib/oas_rails/spec/specification.rb +50 -0
- data/lib/oas_rails/spec/tag.rb +18 -0
- data/lib/oas_rails/utils.rb +59 -0
- data/lib/oas_rails/version.rb +1 -1
- data/lib/oas_rails.rb +41 -16
- metadata +29 -17
- data/lib/oas_rails/contact.rb +0 -12
- data/lib/oas_rails/license.rb +0 -11
- data/lib/oas_rails/media_type.rb +0 -102
- data/lib/oas_rails/oas_base.rb +0 -30
- data/lib/oas_rails/operation.rb +0 -134
- data/lib/oas_rails/parameter.rb +0 -47
- data/lib/oas_rails/path_item.rb +0 -25
- data/lib/oas_rails/paths.rb +0 -19
- data/lib/oas_rails/request_body.rb +0 -29
- data/lib/oas_rails/response.rb +0 -12
- data/lib/oas_rails/responses.rb +0 -20
- data/lib/oas_rails/server.rb +0 -10
- data/lib/oas_rails/specification.rb +0 -72
- data/lib/oas_rails/tag.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85ae0895f424fb76a5e8b50b5f56c82f526a354ec5e9ec562f76219942da99a4
|
4
|
+
data.tar.gz: bcfa9af3b8500e7204b4143173f86ef17d7c36083dfd44490047b7f0beac0c44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b6543957203039aec05ac6c324bd334df075871963f60408d257084df4f908fcac5facff6c69d867d02ad3bef02596a948b784d4f70e12ae7350d6c6dcf6632
|
7
|
+
data.tar.gz: 672a557da4a80d153ecc6d37e73ddabecbc1ad03b7556470cca2f038964214fcb061cedec7866cfe1a2b7e87a3ea77496e0f82e14d182c470e24e4ebcd0e0355
|
data/README.md
CHANGED
@@ -39,6 +39,7 @@ The goal is to minimize the effort required to create comprehensive documentatio
|
|
39
39
|
- [Tag Information](#tag-information)
|
40
40
|
- [Optional Settings](#optional-settings)
|
41
41
|
- [Authentication Settings](#authentication-settings)
|
42
|
+
- [Default Responses (Errors)](#default-responses)
|
42
43
|
- [Usage](#usage)
|
43
44
|
- [Documenting Your Endpoints](#documenting-your-endpoints)
|
44
45
|
- [Example](#example-of-documented-endpoints)
|
@@ -110,6 +111,14 @@ Then fill it with your data. Below are the available configuration options:
|
|
110
111
|
- `config.security_schema`: The default security schema used for authentication. Choose a predefined security schema from `[:api_key_cookie, :api_key_header, :api_key_query, :basic, :bearer, :bearer_jwt, :mutual_tls]`.
|
111
112
|
- `config.security_schemas`: Custom security schemas. Follow the [OpenAPI Specification](https://spec.openapis.org/oas/latest.html#security-scheme-object) for defining these schemas.
|
112
113
|
|
114
|
+
### Default Errors
|
115
|
+
|
116
|
+
- `config.set_default_responses`: Determines whether to add default errors responses to endpoint. Default is `true`.
|
117
|
+
|
118
|
+
- `config.possible_default_responses`: Array with possible default errors.(Some will be added depending on the endpoint, example: not_found only works with show/update/delete). Default: [:not_found, :unauthorized, :forbidden]. It should be HTTP status code symbols from the list: `[:not_found, :unauthorized, :forbidden, :internal_server_error, :unprocessable_entity]`
|
119
|
+
|
120
|
+
- `config.response_body_of_default`: body for use in default responses. It must be a Hash. Default: { message: String }
|
121
|
+
|
113
122
|
## Usage
|
114
123
|
|
115
124
|
In addition to the information provided in the initializer file and the data that can be extracted from the routes and methods automatically, it is essential to document your API in the following way. The documentation is created **with the help of YARD**, so the methods are documented with **comment tags**.
|
@@ -86,4 +86,15 @@ OasRails.configure do |config|
|
|
86
86
|
# "in": "header"
|
87
87
|
# }
|
88
88
|
# }
|
89
|
+
|
90
|
+
# ###########################
|
91
|
+
# Default Responses (Errors)
|
92
|
+
# ###########################
|
93
|
+
|
94
|
+
# The default responses errors are setted only if the action allow it.
|
95
|
+
# Example, if you add forbidden then it will be added only if the endpoint requires authentication.
|
96
|
+
# Example: not_found will be setted to the endpoint only if the operation is a show/update/destroy action.
|
97
|
+
# config.set_default_responses = true
|
98
|
+
# config.possible_default_responses = [:not_found, :unauthorized, :forbidden]
|
99
|
+
# config.response_body_of_default = { message: String }
|
89
100
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class ContentBuilder
|
4
|
+
def initialize(specification, context)
|
5
|
+
@context = context || :incoming
|
6
|
+
@specification = specification
|
7
|
+
@media_type = Spec::MediaType.new(specification)
|
8
|
+
end
|
9
|
+
|
10
|
+
def with_schema(schema)
|
11
|
+
@media_type.schema = @specification.components.add_schema(schema)
|
12
|
+
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def with_examples(examples)
|
17
|
+
@media_type.examples = @specification.components.add_example(examples)
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_examples_from_tags(tags)
|
23
|
+
@media_type.examples = @media_type.examples.merge(tags.each_with_object({}).with_index(1) do |(example, result), _index|
|
24
|
+
key = example.text.downcase.gsub(' ', '_')
|
25
|
+
value = {
|
26
|
+
"summary" => example.text,
|
27
|
+
"value" => example.content
|
28
|
+
}
|
29
|
+
result[key] = @specification.components.add_example(value)
|
30
|
+
end)
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def from_model_class(klass)
|
36
|
+
return self unless klass.ancestors.include? ActiveRecord::Base
|
37
|
+
|
38
|
+
model_schema = EsquemaBuilder.send("build_#{@context}_schema", klass:)
|
39
|
+
model_schema["required"] = []
|
40
|
+
schema = { type: "object", properties: { klass.to_s.downcase => model_schema } }
|
41
|
+
examples = Spec::MediaType.search_for_examples_in_tests(klass, context: @context)
|
42
|
+
@media_type.schema = @specification.components.add_schema(schema)
|
43
|
+
@media_type.examples = @media_type.examples.merge(examples)
|
44
|
+
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def build
|
49
|
+
{
|
50
|
+
"application/json": @media_type
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class OperationBuilder
|
4
|
+
include Extractors::OasRouteExtractor
|
5
|
+
|
6
|
+
def initialize(specification)
|
7
|
+
@specification = specification
|
8
|
+
@operation = Spec::Operation.new(specification)
|
9
|
+
end
|
10
|
+
|
11
|
+
def from_oas_route(oas_route)
|
12
|
+
@operation.summary = extract_summary(oas_route:)
|
13
|
+
@operation.operation_id = extract_operation_id(oas_route:)
|
14
|
+
@operation.description = oas_route.docstring
|
15
|
+
@operation.tags = extract_tags(oas_route:)
|
16
|
+
@operation.security = extract_security(oas_route:)
|
17
|
+
@operation.parameters = ParametersBuilder.new(@specification).from_oas_route(oas_route).build
|
18
|
+
@operation.request_body = RequestBodyBuilder.new(@specification).from_oas_route(oas_route).reference
|
19
|
+
@operation.responses = ResponsesBuilder.new(@specification)
|
20
|
+
.from_oas_route(oas_route)
|
21
|
+
.add_autodiscovered_responses(oas_route)
|
22
|
+
.add_default_responses(oas_route, !@operation.security.empty?).build
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def build
|
28
|
+
@operation
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class ParameterBuilder
|
4
|
+
def initialize(specification)
|
5
|
+
@specification = specification
|
6
|
+
@parameter = Spec::Parameter.new(specification)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_path(path, param)
|
10
|
+
@parameter.name = param
|
11
|
+
@parameter.in = 'path'
|
12
|
+
@parameter.description = "#{param.split('_')[-1].titleize} of existing #{extract_word_before(path, param).singularize}."
|
13
|
+
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def extract_word_before(string, param)
|
18
|
+
regex = %r{/(\w+)/\{#{param}\}}
|
19
|
+
match = string.match(regex)
|
20
|
+
match ? match[1] : nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def build
|
24
|
+
@parameter
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class ParametersBuilder
|
4
|
+
def initialize(specification)
|
5
|
+
@specification = specification
|
6
|
+
@parameters = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_oas_route(oas_route)
|
10
|
+
parameters_from_tags(tags: oas_route.docstring.tags(:parameter))
|
11
|
+
oas_route.path_params.try(:map) do |p|
|
12
|
+
@parameters << ParameterBuilder.new(@specification).from_path(oas_route.path, p).build unless @parameters.any? { |param| param.name.to_s == p.to_s }
|
13
|
+
end
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def parameters_from_tags(tags:)
|
19
|
+
tags.each do |t|
|
20
|
+
parameter = Spec::Parameter.new(@specification)
|
21
|
+
parameter.name = t.name
|
22
|
+
parameter.in = t.location
|
23
|
+
parameter.required = t.required
|
24
|
+
parameter.schema = t.schema
|
25
|
+
parameter.description = t.text
|
26
|
+
@parameters << parameter
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def build
|
33
|
+
@parameters.map do |p|
|
34
|
+
@specification.components.add_parameter(p)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class PathItemBuilder
|
4
|
+
def initialize(specification)
|
5
|
+
@specification = specification
|
6
|
+
@path_item = Spec::PathItem.new(specification)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_path(path, route_extractor: Extractors::RouteExtractor)
|
10
|
+
route_extractor.host_routes_by_path(path).each do |oas_route|
|
11
|
+
@path_item.add_operation(oas_route.verb.downcase, OperationBuilder.new(@specification).from_oas_route(oas_route).build)
|
12
|
+
end
|
13
|
+
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def build
|
18
|
+
@path_item
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class RequestBodyBuilder
|
4
|
+
def initialize(specification)
|
5
|
+
@specification = specification
|
6
|
+
@request_body = Spec::RequestBody.new(specification)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_oas_route(oas_route)
|
10
|
+
tag_request_body = oas_route.docstring.tags(:request_body).first
|
11
|
+
if tag_request_body.nil? && OasRails.config.autodiscover_request_body
|
12
|
+
detect_request_body(oas_route) if %w[create update].include? oas_route.method
|
13
|
+
elsif !tag_request_body.nil?
|
14
|
+
from_tags(tag: tag_request_body, examples_tags: oas_route.docstring.tags(:request_body_example))
|
15
|
+
end
|
16
|
+
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def from_tags(tag:, examples_tags: [])
|
21
|
+
if tag.klass.ancestors.include? ActiveRecord::Base
|
22
|
+
from_model_class(klass: tag.klass, description: tag.text, required: tag.required, examples_tags:)
|
23
|
+
else
|
24
|
+
@request_body.description = tag.text
|
25
|
+
@request_body.content = ContentBuilder.new(@specification, :incoming).with_schema(tag.schema).with_examples_from_tags(examples_tags).build
|
26
|
+
@request_body.required = tag.required
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def from_model_class(klass:, **kwargs)
|
33
|
+
@request_body.description = kwargs[:description] || klass.to_s
|
34
|
+
@request_body.content = ContentBuilder.new(@specification, :incoming).from_model_class(klass).with_examples_from_tags(kwargs[:examples_tags] || {}).build
|
35
|
+
@request_body.required = kwargs[:required]
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def build
|
41
|
+
return {} if @request_body.content == {}
|
42
|
+
|
43
|
+
@request_body
|
44
|
+
end
|
45
|
+
|
46
|
+
def reference
|
47
|
+
return {} if @request_body.content == {}
|
48
|
+
|
49
|
+
@specification.components.add_request_body(@request_body)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def detect_request_body(oas_route)
|
55
|
+
return unless (klass = Utils.find_model_from_route(oas_route.controller))
|
56
|
+
|
57
|
+
from_model_class(klass:, required: true)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class ResponseBuilder
|
4
|
+
def initialize(specification)
|
5
|
+
@specification = specification
|
6
|
+
@response = Spec::Response.new(specification)
|
7
|
+
end
|
8
|
+
|
9
|
+
def with_description(description)
|
10
|
+
@response.description = description
|
11
|
+
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_content(content)
|
16
|
+
@response.content = content
|
17
|
+
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def with_code(code)
|
22
|
+
@response.code = code
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def from_tag(tag)
|
28
|
+
@response.code = tag.name.to_i
|
29
|
+
@response.description = tag.text
|
30
|
+
@response.content = ContentBuilder.new(@specification, :outgoing).with_schema(tag.schema).build
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def build
|
36
|
+
@response
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Builders
|
3
|
+
class ResponsesBuilder
|
4
|
+
def initialize(specification)
|
5
|
+
@specification = specification
|
6
|
+
@responses = Spec::Responses.new(specification)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_oas_route(oas_route)
|
10
|
+
oas_route.docstring.tags(:response).each do |tag|
|
11
|
+
@responses.add_response(ResponseBuilder.new(@specification).from_tag(tag).build)
|
12
|
+
end
|
13
|
+
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_autodiscovered_responses(oas_route)
|
18
|
+
return unless OasRails.config.autodiscover_responses
|
19
|
+
|
20
|
+
new_responses = Extractors::RenderResponseExtractor.extract_responses_from_source(@specification, source: oas_route.source_string)
|
21
|
+
|
22
|
+
new_responses.each do |new_response|
|
23
|
+
@responses.add_response(new_response) if @responses.responses[new_response.code].blank?
|
24
|
+
end
|
25
|
+
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_default_responses(oas_route, security)
|
30
|
+
return unless OasRails.config.set_default_responses
|
31
|
+
|
32
|
+
content = ContentBuilder.new(@specification, :outgoing).with_schema(Utils.hash_to_json_schema(OasRails.config.response_body_of_default)).build
|
33
|
+
common_errors = []
|
34
|
+
common_errors.push(:unauthorized, :forbidden) if security
|
35
|
+
|
36
|
+
case oas_route.method
|
37
|
+
when "show", "update", "destroy"
|
38
|
+
common_errors.push(:not_found)
|
39
|
+
when "create", "index"
|
40
|
+
# possible errors for this methods?
|
41
|
+
end
|
42
|
+
|
43
|
+
(OasRails.config.possible_default_responses & common_errors).each do |e|
|
44
|
+
code = Utils.status_to_integer(e)
|
45
|
+
response = ResponseBuilder.new(@specification).with_code(code).with_description(Utils.get_definition(code)).with_content(content).build
|
46
|
+
|
47
|
+
@responses.add_response(response) if @responses.responses[response.code].blank?
|
48
|
+
end
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def build
|
54
|
+
@responses
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,10 +1,19 @@
|
|
1
1
|
module OasRails
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :info,
|
3
|
+
attr_accessor :info,
|
4
|
+
:default_tags_from,
|
5
|
+
:autodiscover_request_body,
|
6
|
+
:autodiscover_responses,
|
7
|
+
:api_path,
|
8
|
+
:security_schemas,
|
9
|
+
:authenticate_all_routes_by_default,
|
10
|
+
:set_default_responses,
|
11
|
+
:possible_default_responses,
|
12
|
+
:response_body_of_default
|
4
13
|
attr_reader :servers, :tags, :security_schema
|
5
14
|
|
6
15
|
def initialize
|
7
|
-
@info = Info.new
|
16
|
+
@info = Spec::Info.new
|
8
17
|
@servers = default_servers
|
9
18
|
@tags = []
|
10
19
|
@swagger_version = '3.1.0'
|
@@ -15,6 +24,9 @@ module OasRails
|
|
15
24
|
@authenticate_all_routes_by_default = true
|
16
25
|
@security_schema = nil
|
17
26
|
@security_schemas = {}
|
27
|
+
@set_default_responses = true
|
28
|
+
@possible_default_responses = [:not_found, :unauthorized, :forbidden]
|
29
|
+
@response_body_of_default = { message: String }
|
18
30
|
end
|
19
31
|
|
20
32
|
def security_schema=(value)
|
@@ -24,15 +36,15 @@ module OasRails
|
|
24
36
|
end
|
25
37
|
|
26
38
|
def default_servers
|
27
|
-
[Server.new(url: "http://localhost:3000", description: "Rails Default Development Server")]
|
39
|
+
[Spec::Server.new(url: "http://localhost:3000", description: "Rails Default Development Server")]
|
28
40
|
end
|
29
41
|
|
30
42
|
def servers=(value)
|
31
|
-
@servers = value.map { |s| Server.new(url: s[:url], description: s[:description]) }
|
43
|
+
@servers = value.map { |s| Spec::Server.new(url: s[:url], description: s[:description]) }
|
32
44
|
end
|
33
45
|
|
34
46
|
def tags=(value)
|
35
|
-
@tags = value.map { |t| Tag.new(name: t[:name], description: t[:description]) }
|
47
|
+
@tags = value.map { |t| Spec::Tag.new(name: t[:name], description: t[:description]) }
|
36
48
|
end
|
37
49
|
|
38
50
|
def excluded_columns_incoming
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Extractors
|
3
|
+
module OasRouteExtractor
|
4
|
+
def extract_summary(oas_route:)
|
5
|
+
oas_route.docstring.tags(:summary).first.try(:text) || generate_crud_name(oas_route.method, oas_route.controller.downcase) || "#{oas_route.verb} #{oas_route.path}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def extract_operation_id(oas_route:)
|
9
|
+
"#{oas_route.method}#{oas_route.path.gsub('/', '_').gsub(/[{}]/, '')}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def extract_tags(oas_route:)
|
13
|
+
tags = oas_route.docstring.tags(:tags).first
|
14
|
+
if tags.nil?
|
15
|
+
default_tags(oas_route:)
|
16
|
+
else
|
17
|
+
tags.text.split(",").map(&:strip).map(&:titleize)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_tags(oas_route:)
|
22
|
+
tags = []
|
23
|
+
if OasRails.config.default_tags_from == "namespace"
|
24
|
+
tag = oas_route.path.split('/').reject(&:empty?).first.try(:titleize)
|
25
|
+
tags << tag unless tag.nil?
|
26
|
+
else
|
27
|
+
tags << oas_route.controller.titleize
|
28
|
+
end
|
29
|
+
tags
|
30
|
+
end
|
31
|
+
|
32
|
+
def extract_security(oas_route:)
|
33
|
+
return [] if oas_route.docstring.tags(:no_auth).any?
|
34
|
+
|
35
|
+
if (methods = oas_route.docstring.tags(:auth).first)
|
36
|
+
OasRails.config.security_schemas.keys.map { |key| { key => [] } }.select do |schema|
|
37
|
+
methods.types.include?(schema.keys.first.to_s)
|
38
|
+
end
|
39
|
+
elsif OasRails.config.authenticate_all_routes_by_default
|
40
|
+
OasRails.config.security_schemas.keys.map { |key| { key => [] } }
|
41
|
+
else
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def generate_crud_name(method, controller)
|
49
|
+
controller_name = controller.to_s.underscore.humanize.downcase.pluralize
|
50
|
+
|
51
|
+
case method.to_sym
|
52
|
+
when :index
|
53
|
+
"List #{controller_name}"
|
54
|
+
when :show
|
55
|
+
"View #{controller_name.singularize}"
|
56
|
+
when :create
|
57
|
+
"Create new #{controller_name.singularize}"
|
58
|
+
when :update
|
59
|
+
"Update #{controller_name.singularize}"
|
60
|
+
when :destroy
|
61
|
+
"Delete #{controller_name.singularize}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -7,12 +7,11 @@ module OasRails
|
|
7
7
|
#
|
8
8
|
# @param source [String] The source string containing render calls.
|
9
9
|
# @return [Array<Response>] An array of Response objects extracted from the source.
|
10
|
-
def extract_responses_from_source(source:)
|
10
|
+
def extract_responses_from_source(specification, source:)
|
11
11
|
render_calls = extract_render_calls(source)
|
12
|
+
return [Builders::ResponseBuilder.new(specification).with_description("No content").with_code(204).build] if render_calls.empty?
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
render_calls.map { |render_content, status| process_render_content(render_content.strip, status) }
|
14
|
+
render_calls.map { |render_content, status| process_render_content(specification, render_content.strip, status) }
|
16
15
|
end
|
17
16
|
|
18
17
|
private
|
@@ -30,14 +29,12 @@ module OasRails
|
|
30
29
|
# @param content [String] The content extracted from the render call.
|
31
30
|
# @param status [String] The status code associated with the render call.
|
32
31
|
# @return [Response] A Response object based on the processed content and status.
|
33
|
-
def process_render_content(content, status)
|
32
|
+
def process_render_content(specification, content, status)
|
34
33
|
schema, examples = build_schema_and_examples(content)
|
35
|
-
status_int = status_to_integer(status)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
content: { "application/json": MediaType.new(schema:, examples:) }
|
40
|
-
)
|
34
|
+
status_int = Utils.status_to_integer(status)
|
35
|
+
content = Builders::ContentBuilder.new(specification, :outgoing).with_schema(schema).with_examples(examples).build
|
36
|
+
|
37
|
+
Builders::ResponseBuilder.new(specification).with_code(status_int).with_description(Utils.status_code_to_text(status_int)).with_content(content).build
|
41
38
|
end
|
42
39
|
|
43
40
|
# Builds schema and examples based on the content type.
|
@@ -84,8 +81,9 @@ module OasRails
|
|
84
81
|
# @return [Array<Hash, Hash>] An array where the first element is the schema and the second is the examples.
|
85
82
|
def build_singular_model_schema_and_examples(_maybe_a_model, errors, klass, schema)
|
86
83
|
if errors.nil?
|
87
|
-
[schema, MediaType.search_for_examples_in_tests(klass
|
84
|
+
[schema, Spec::MediaType.search_for_examples_in_tests(klass, context: :outgoing)]
|
88
85
|
else
|
86
|
+
# TODO: this is not building the real schema.
|
89
87
|
[
|
90
88
|
{
|
91
89
|
type: "object",
|
@@ -112,7 +110,7 @@ module OasRails
|
|
112
110
|
# @param schema [Hash] The schema for the model.
|
113
111
|
# @return [Array<Hash, Hash>] An array where the first element is the schema and the second is the examples.
|
114
112
|
def build_array_model_schema_and_examples(maybe_a_model, klass, schema)
|
115
|
-
examples = { maybe_a_model => { value: MediaType.search_for_examples_in_tests(klass
|
113
|
+
examples = { maybe_a_model => { value: Spec::MediaType.search_for_examples_in_tests(klass, context: :outgoing).values.map { |p| p.dig(:value, maybe_a_model.singularize.to_sym) } } }
|
116
114
|
[{ type: "array", items: schema }, examples]
|
117
115
|
end
|
118
116
|
|
@@ -144,29 +142,6 @@ module OasRails
|
|
144
142
|
|
145
143
|
structure
|
146
144
|
end
|
147
|
-
|
148
|
-
# Converts a status symbol or string to an integer.
|
149
|
-
#
|
150
|
-
# @param status [String, Symbol, nil] The status to convert.
|
151
|
-
# @return [Integer] The status code as an integer.
|
152
|
-
def status_to_integer(status)
|
153
|
-
return 200 if status.nil?
|
154
|
-
|
155
|
-
if status.to_s =~ /^\d+$/
|
156
|
-
status.to_i
|
157
|
-
else
|
158
|
-
status = "unprocessable_content" if status == "unprocessable_entity"
|
159
|
-
Rack::Utils::SYMBOL_TO_STATUS_CODE[status.to_sym]
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# Converts a status code to its corresponding text description.
|
164
|
-
#
|
165
|
-
# @param status_code [Integer] The status code.
|
166
|
-
# @return [String] The text description of the status code.
|
167
|
-
def status_code_to_text(status_code)
|
168
|
-
Rack::Utils::HTTP_STATUS_CODES[status_code] || "Unknown Status Code"
|
169
|
-
end
|
170
145
|
end
|
171
146
|
end
|
172
147
|
end
|
data/lib/oas_rails/oas_route.rb
CHANGED
@@ -41,10 +41,5 @@ module OasRails
|
|
41
41
|
def controller_path_extractor(controller)
|
42
42
|
Rails.root.join("app/controllers/#{controller}_controller.rb").to_s
|
43
43
|
end
|
44
|
-
|
45
|
-
def detect_request_body
|
46
|
-
klass = @controller.singularize.camelize.constantize
|
47
|
-
RequestBody.from_model_class(klass:, required: true)
|
48
|
-
end
|
49
44
|
end
|
50
45
|
end
|