oas_rails 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +674 -0
- data/README.md +119 -9
- data/app/controllers/oas_rails/application_controller.rb +1 -0
- data/app/controllers/oas_rails/oas_rails_controller.rb +7 -4
- data/app/views/oas_rails/oas_rails/index.html.erb +1 -1
- data/config/routes.rb +1 -2
- data/lib/generators/oas_rails/config/templates/oas_rails_initializer.rb +45 -6
- data/lib/oas_rails/configuration.rb +54 -4
- data/lib/oas_rails/media_type.rb +1 -1
- data/lib/oas_rails/oas_base.rb +2 -1
- data/lib/oas_rails/oas_route.rb +1 -1
- data/lib/oas_rails/operation.rb +18 -2
- data/lib/oas_rails/specification.rb +26 -6
- data/lib/oas_rails/utils.rb +66 -0
- data/lib/oas_rails/version.rb +1 -1
- data/lib/oas_rails/yard/oas_yard_factory.rb +3 -3
- data/lib/oas_rails.rb +30 -82
- metadata +12 -21
- data/MIT-LICENSE +0 -20
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
![Gem Version](https://img.shields.io/gem/v/oas_rails)
|
2
2
|
![GitHub License](https://img.shields.io/github/license/a-chacon/oas_rails)
|
3
|
+
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/a-chacon/oas_rails/.github%2Fworkflows%2Frubyonrails.yml)
|
3
4
|
|
4
5
|
# Open API Specification For Rails
|
5
6
|
|
@@ -39,15 +40,15 @@ The goal is to minimize the effort required to create comprehensive documentatio
|
|
39
40
|
|
40
41
|
2. Execute:
|
41
42
|
|
42
|
-
```bash
|
43
|
-
bundle
|
44
|
-
```
|
43
|
+
```bash
|
44
|
+
bundle
|
45
|
+
```
|
45
46
|
|
46
47
|
3. Mount the engine in your config/routes.rb file
|
47
48
|
|
48
|
-
```ruby
|
49
|
-
mount OasRails::Engine => '/docs'
|
50
|
-
```
|
49
|
+
```ruby
|
50
|
+
mount OasRails::Engine => '/docs'
|
51
|
+
```
|
51
52
|
|
52
53
|
You'll now have **basic documentation** based on your routes and automatically gathered information at `localhost:3000/docs`. To enhance it, create an initializer file and add [Yard](https://yardoc.org/) tags to your controller methods.
|
53
54
|
|
@@ -57,7 +58,7 @@ You'll now have **basic documentation** based on your routes and automatically g
|
|
57
58
|
|
58
59
|
You can easy create the initializer file with:
|
59
60
|
|
60
|
-
```
|
61
|
+
```bash
|
61
62
|
rails generate oas_rails:config
|
62
63
|
```
|
63
64
|
|
@@ -65,6 +66,89 @@ Then complete the created file with your data.
|
|
65
66
|
|
66
67
|
**Almost every description in a OAS file support simple markdown**
|
67
68
|
|
69
|
+
## Configuration
|
70
|
+
|
71
|
+
To configure OasRails, edit the `config/initializers/oas_rails.rb` file. Below are the available configuration options:
|
72
|
+
|
73
|
+
### Basic Information about the API
|
74
|
+
|
75
|
+
- `config.info.title`: The title of your API documentation.
|
76
|
+
- `config.info.summary`: A brief summary of your API.
|
77
|
+
- `config.info.description`: A detailed description of your API. This can include markdown formatting and will be displayed prominently in your documentation.
|
78
|
+
- `config.info.contact.name`: The name of the contact person or organization.
|
79
|
+
- `config.info.contact.email`: The contact email address.
|
80
|
+
- `config.info.contact.url`: The URL for more information or support.
|
81
|
+
|
82
|
+
### Servers Information
|
83
|
+
|
84
|
+
- `config.servers`: An array of server objects, each containing `url` and `description` keys. For more details, refer to the [OpenAPI Specification](https://spec.openapis.org/oas/latest.html#server-object).
|
85
|
+
|
86
|
+
### Tag Information
|
87
|
+
|
88
|
+
- `config.tags`: An array of tag objects, each containing `name` and `description` keys. For more details, refer to the [OpenAPI Specification](https://spec.openapis.org/oas/latest.html#tag-object).
|
89
|
+
|
90
|
+
### Optional Settings
|
91
|
+
|
92
|
+
- `config.default_tags_from`: Determines the source of default tags for operations. Can be set to `:namespace` or `:controller`.
|
93
|
+
- `config.autodiscover_request_body`: Automatically detects request bodies for create/update methods. Default is `true`.
|
94
|
+
- `config.autodiscover_responses`: Automatically detects responses from controller renders. Default is `true`.
|
95
|
+
- `config.api_path`: Sets the API path if your API is under a different namespace.
|
96
|
+
|
97
|
+
### Authentication Settings
|
98
|
+
|
99
|
+
- `config.authenticate_all_routes_by_default`: Determines whether to authenticate all routes by default. Default is `true`.
|
100
|
+
- `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]`.
|
101
|
+
- `config.security_schemas`: Custom security schemas. Follow the [OpenAPI Specification](https://spec.openapis.org/oas/latest.html#security-scheme-object) for defining these schemas.
|
102
|
+
|
103
|
+
## Securing the OasRails Engine
|
104
|
+
|
105
|
+
To secure the OasRails engine, which exposes an endpoint for showing the OAS definition, you can configure authentication to ensure that only authorized users have access. Here are a few methods to achieve this:
|
106
|
+
|
107
|
+
### 1. Using Basic Authentication
|
108
|
+
|
109
|
+
Use basic authentication to protect the OasRails endpoint. You can set this up in an initializer:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
# config/initializers/oas_rails.rb
|
113
|
+
OasRails::Engine.middleware.use(Rack::Auth::Basic) do |username, password|
|
114
|
+
ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.oas_rails_username, username) &
|
115
|
+
ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.oas_rails_password, password)
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
### 2. Using Devise's `authenticate` Helper
|
120
|
+
|
121
|
+
You can use Devise's `authenticate` helper to restrict access to the OasRails endpoint. For example, you can allow only admin users to access the endpoint:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
# config/routes.rb
|
125
|
+
# ...
|
126
|
+
authenticate :user, ->(user) { user.admin? } do
|
127
|
+
mount OasRails::Engine, at: '/docs'
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
### 3. Custom Authentication
|
132
|
+
|
133
|
+
To support custom authentication, you can extend the OasRails' ApplicationController using a hook. This allows you to add custom before actions to check for specific user permissions:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
# config/initializers/oas_rails.rb
|
137
|
+
|
138
|
+
ActiveSupport.on_load(:oas_rails_application_controller) do
|
139
|
+
# context here is OasRails::ApplicationController
|
140
|
+
|
141
|
+
before_action do
|
142
|
+
raise ActionController::RoutingError.new('Not Found') unless current_user&.admin?
|
143
|
+
end
|
144
|
+
|
145
|
+
def current_user
|
146
|
+
# Load the current user
|
147
|
+
User.find(session[:user_id]) # Adjust according to your authentication logic
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
68
152
|
## Documenting Your Endpoints
|
69
153
|
|
70
154
|
Almost every description in an OAS file supports simple markdown. The following tags are available for documenting your endpoints:
|
@@ -142,6 +226,30 @@ Tags your endpoints. You can complete the tag documentation in the initializer f
|
|
142
226
|
|
143
227
|
</details>
|
144
228
|
|
229
|
+
<details>
|
230
|
+
<summary style="font-weight: bold; font-size: 1.2em;">@no_auth</summary>
|
231
|
+
|
232
|
+
**Structure**: `@no_auth`
|
233
|
+
|
234
|
+
This tag will remove any security requirement from the endpoint. Useful when most of your endpoints require authentication and only a few do not.(Ex: Login, Registration...)
|
235
|
+
|
236
|
+
**Example**:
|
237
|
+
`# @no_auth`
|
238
|
+
|
239
|
+
</details>
|
240
|
+
|
241
|
+
<details>
|
242
|
+
<summary style="font-weight: bold; font-size: 1.2em;">@auth</summary>
|
243
|
+
|
244
|
+
**Structure**: `@auth [types]`
|
245
|
+
|
246
|
+
This tag will set which security mechanisms can be used for the endpoint. The security mechanisms MUST be defined previously in the initializer file.
|
247
|
+
|
248
|
+
**Example**:
|
249
|
+
`# @auth [bearer, basic]`
|
250
|
+
|
251
|
+
</details>
|
252
|
+
|
145
253
|
You can use these tags in your controller methods to enhance the automatically generated documentation. Remember to use markdown formatting in your descriptions for better readability in the generated OAS document.
|
146
254
|
|
147
255
|
### Example of documented endpoints
|
@@ -160,6 +268,7 @@ class UsersController < ApplicationController
|
|
160
268
|
end
|
161
269
|
|
162
270
|
# @summary Get a user by id.
|
271
|
+
# @auth [bearer]
|
163
272
|
#
|
164
273
|
# This method show a User by ID. The id must exist of other way it will be returning a **`404`**.
|
165
274
|
#
|
@@ -172,6 +281,7 @@ class UsersController < ApplicationController
|
|
172
281
|
end
|
173
282
|
|
174
283
|
# @summary Create a User
|
284
|
+
# @no_auth
|
175
285
|
#
|
176
286
|
# @request_body The user to be created. At least include an `email`. [User!]
|
177
287
|
# @request_body_example basic user [Hash] {user: {name: "Luis", email: "luis@gmail.ocom"}}
|
@@ -234,12 +344,12 @@ Contributions are what make the open source community such an amazing place to l
|
|
234
344
|
### Roadmap and Ideas for Improvement
|
235
345
|
|
236
346
|
- Clean, document and structure the code
|
237
|
-
- Support documentation of authentication methods
|
347
|
+
- [x] Support documentation of authentication methods
|
238
348
|
- Define Global Tags/Configuration (e.g., common responses like 404 errors)
|
239
349
|
- Post-process the JSON and replace common objects with references to components
|
240
350
|
- Create a temporary file with the JSON in production mode to avoid rebuilding it on every request
|
241
351
|
- Create tags for popular gems used in APIs (e.g., a `@pagy` tag for common pagination parameters)
|
242
|
-
- Add basic authentication to OAS and UI for security reasons
|
352
|
+
- [x] Add basic authentication to OAS and UI for security reasons (Solution documented, not need to be managed by the engine)
|
243
353
|
- Implement ability to define OAS by namespaces (e.g., generate OAS for specific routes like `/api` or separate versions V1 and V2)
|
244
354
|
|
245
355
|
## License
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module OasRails
|
2
2
|
class OasRailsController < ApplicationController
|
3
|
-
def index
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
def index
|
4
|
+
respond_to do |format|
|
5
|
+
format.html
|
6
|
+
format.json do
|
7
|
+
render json: Specification.new.to_json, status: :ok
|
8
|
+
end
|
9
|
+
end
|
7
10
|
end
|
8
11
|
end
|
9
12
|
end
|
@@ -1 +1 @@
|
|
1
|
-
<rapi-doc spec-url = "<%= main_app.oas_rails_path
|
1
|
+
<rapi-doc spec-url = "<%= main_app.oas_rails_path %>.json" theme = "dark" text-color="#f9f9f9" show-header = 'false'> </rapi-doc>
|
data/config/routes.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# config/initializers/oas_rails.rb
|
2
2
|
OasRails.configure do |config|
|
3
|
+
# Basic Information about the API
|
3
4
|
config.info.title = 'OasRails'
|
4
5
|
config.info.summary = 'OasRails: Automatic Interactive API Documentation for Rails'
|
5
6
|
config.info.description = <<~HEREDOC
|
@@ -34,17 +35,55 @@ OasRails.configure do |config|
|
|
34
35
|
Explore your API documentation and enjoy the power of OasRails!
|
35
36
|
|
36
37
|
For more information and advanced usage, visit the [OasRails GitHub repository](https://github.com/a-chacon/oas_rails).
|
37
|
-
|
38
|
-
|
39
38
|
HEREDOC
|
40
39
|
config.info.contact.name = 'a-chacon'
|
41
40
|
config.info.contact.email = 'andres.ch@proton.me'
|
42
41
|
config.info.contact.url = 'https://a-chacon.com'
|
42
|
+
|
43
|
+
# Servers Information. For more details follow: https://spec.openapis.org/oas/latest.html#server-object
|
43
44
|
config.servers = [{ url: 'http://localhost:3000', description: 'Local' }]
|
45
|
+
|
46
|
+
# Tag Information. For more details follow: https://spec.openapis.org/oas/latest.html#tag-object
|
44
47
|
config.tags = [{ name: "Users", description: "Manage the `amazing` Users table." }]
|
45
48
|
|
46
|
-
#
|
47
|
-
|
48
|
-
#
|
49
|
-
# config.
|
49
|
+
# Optional Settings (Uncomment to use)
|
50
|
+
|
51
|
+
# Extract default tags of operations from namespace or controller. Can be set to :namespace or :controller
|
52
|
+
# config.default_tags_from = :namespace
|
53
|
+
|
54
|
+
# Automatically detect request bodies for create/update methods
|
55
|
+
# Default: true
|
56
|
+
# config.autodiscover_request_body = false
|
57
|
+
|
58
|
+
# Automatically detect responses from controller renders
|
59
|
+
# Default: true
|
60
|
+
# config.autodiscover_responses = false
|
61
|
+
|
62
|
+
# API path configuration if your API is under a different namespace
|
63
|
+
# config.api_path = "/"
|
64
|
+
|
65
|
+
# #######################
|
66
|
+
# Authentication Settings
|
67
|
+
# #######################
|
68
|
+
|
69
|
+
# Whether to authenticate all routes by default
|
70
|
+
# Default is true; set to false if you don't want all routes to include secutrity schemas by default
|
71
|
+
# config.authenticate_all_routes_by_default = true
|
72
|
+
|
73
|
+
# Default security schema used for authentication
|
74
|
+
# Choose a predefined security schema
|
75
|
+
# [:api_key_cookie, :api_key_header, :api_key_query, :basic, :bearer, :bearer_jwt, :mutual_tls]
|
76
|
+
# config.security_schema = :bearer
|
77
|
+
|
78
|
+
# Custom security schemas
|
79
|
+
# You can uncomment and modify to use custom security schemas
|
80
|
+
# Please follow the documentation: https://spec.openapis.org/oas/latest.html#security-scheme-object
|
81
|
+
#
|
82
|
+
# config.security_schemas = {
|
83
|
+
# bearer:{
|
84
|
+
# "type": "apiKey",
|
85
|
+
# "name": "api_key",
|
86
|
+
# "in": "header"
|
87
|
+
# }
|
88
|
+
# }
|
50
89
|
end
|
@@ -1,17 +1,26 @@
|
|
1
1
|
module OasRails
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :info, :default_tags_from, :autodiscover_request_body, :autodiscover_responses, :api_path
|
4
|
-
attr_reader :servers, :tags
|
3
|
+
attr_accessor :info, :default_tags_from, :autodiscover_request_body, :autodiscover_responses, :api_path, :security_schemas, :authenticate_all_routes_by_default
|
4
|
+
attr_reader :servers, :tags, :security_schema
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize
|
7
7
|
@info = Info.new
|
8
|
-
@servers =
|
8
|
+
@servers = default_servers
|
9
9
|
@tags = []
|
10
10
|
@swagger_version = '3.1.0'
|
11
11
|
@default_tags_from = "namespace"
|
12
12
|
@autodiscover_request_body = true
|
13
13
|
@autodiscover_responses = true
|
14
14
|
@api_path = "/"
|
15
|
+
@authenticate_all_routes_by_default = true
|
16
|
+
@security_schema = nil
|
17
|
+
@security_schemas = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def security_schema=(value)
|
21
|
+
return unless (security_schema = DEFAULT_SECURITY_SCHEMES[value])
|
22
|
+
|
23
|
+
@security_schemas = { value => security_schema }
|
15
24
|
end
|
16
25
|
|
17
26
|
def default_servers
|
@@ -26,4 +35,45 @@ module OasRails
|
|
26
35
|
@tags = value.map { |t| Tag.new(name: t[:name], description: t[:description]) }
|
27
36
|
end
|
28
37
|
end
|
38
|
+
|
39
|
+
DEFAULT_SECURITY_SCHEMES = {
|
40
|
+
api_key_cookie: {
|
41
|
+
type: "apiKey",
|
42
|
+
in: "cookie",
|
43
|
+
name: "api_key",
|
44
|
+
description: "An API key that will be supplied in a named cookie."
|
45
|
+
},
|
46
|
+
api_key_header: {
|
47
|
+
type: "apiKey",
|
48
|
+
in: "header",
|
49
|
+
name: "X-API-Key",
|
50
|
+
description: "An API key that will be supplied in a named header."
|
51
|
+
},
|
52
|
+
api_key_query: {
|
53
|
+
type: "apiKey",
|
54
|
+
in: "query",
|
55
|
+
name: "apiKey",
|
56
|
+
description: "An API key that will be supplied in a named query parameter."
|
57
|
+
},
|
58
|
+
basic: {
|
59
|
+
type: "http",
|
60
|
+
scheme: "basic",
|
61
|
+
description: "Basic auth that takes a base64'd combination of `user:password`."
|
62
|
+
},
|
63
|
+
bearer: {
|
64
|
+
type: "http",
|
65
|
+
scheme: "bearer",
|
66
|
+
description: "A bearer token that will be supplied within an `Authorization` header as `bearer <token>`."
|
67
|
+
},
|
68
|
+
bearer_jwt: {
|
69
|
+
type: "http",
|
70
|
+
scheme: "bearer",
|
71
|
+
bearerFormat: "JWT",
|
72
|
+
description: "A bearer token that will be supplied within an `Authorization` header as `bearer <token>`. In this case, the format of the token is specified as JWT."
|
73
|
+
},
|
74
|
+
mutual_tls: {
|
75
|
+
type: "mutualTLS",
|
76
|
+
description: "Requires a specific mutual TLS certificate to use when making an HTTP request."
|
77
|
+
}
|
78
|
+
}.freeze
|
29
79
|
end
|
data/lib/oas_rails/media_type.rb
CHANGED
data/lib/oas_rails/oas_base.rb
CHANGED
@@ -13,7 +13,8 @@ module OasRails
|
|
13
13
|
value
|
14
14
|
end
|
15
15
|
|
16
|
-
hash[camel_case_key] = processed_value unless (processed_value.is_a?(Hash) || processed_value.is_a?(Array)) && processed_value.empty?
|
16
|
+
# hash[camel_case_key] = processed_value unless (processed_value.is_a?(Hash) || processed_value.is_a?(Array)) && processed_value.empty?
|
17
|
+
hash[camel_case_key] = processed_value
|
17
18
|
end
|
18
19
|
hash
|
19
20
|
end
|
data/lib/oas_rails/oas_route.rb
CHANGED
@@ -59,7 +59,7 @@ module OasRails
|
|
59
59
|
schema = {}
|
60
60
|
begin
|
61
61
|
schema = if content.start_with?('{')
|
62
|
-
|
62
|
+
Utils.hash_to_json_schema(parse_hash_structure(content))
|
63
63
|
else
|
64
64
|
# It's likely a variable or method call
|
65
65
|
maybe_a_model, errors = content.gsub('@', "").split(".")
|
data/lib/oas_rails/operation.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module OasRails
|
2
2
|
class Operation < OasBase
|
3
|
-
attr_accessor :tags, :summary, :description, :operation_id, :parameters, :method, :docstring, :request_body, :responses
|
3
|
+
attr_accessor :tags, :summary, :description, :operation_id, :parameters, :method, :docstring, :request_body, :responses, :security
|
4
4
|
|
5
5
|
def initialize(method:, summary:, operation_id:, **kwargs)
|
6
6
|
super()
|
@@ -12,6 +12,7 @@ module OasRails
|
|
12
12
|
@parameters = kwargs[:parameters] || []
|
13
13
|
@request_body = kwargs[:request_body] || {}
|
14
14
|
@responses = kwargs[:responses] || {}
|
15
|
+
@security = kwargs[:security] || []
|
15
16
|
end
|
16
17
|
|
17
18
|
class << self
|
@@ -23,7 +24,8 @@ module OasRails
|
|
23
24
|
parameters = extract_parameters(oas_route:)
|
24
25
|
request_body = extract_request_body(oas_route:)
|
25
26
|
responses = extract_responses(oas_route:)
|
26
|
-
|
27
|
+
security = extract_security(oas_route:)
|
28
|
+
new(method: oas_route.verb.downcase, summary:, operation_id:, tags:, description:, parameters:, request_body:, responses:, security:)
|
27
29
|
end
|
28
30
|
|
29
31
|
def extract_summary(oas_route:)
|
@@ -112,6 +114,20 @@ module OasRails
|
|
112
114
|
responses
|
113
115
|
end
|
114
116
|
|
117
|
+
def extract_security(oas_route:)
|
118
|
+
return [] if oas_route.docstring.tags(:no_auth).any?
|
119
|
+
|
120
|
+
if (methods = oas_route.docstring.tags(:auth).first)
|
121
|
+
OasRails.config.security_schemas.keys.map { |key| { key => [] } }.select do |schema|
|
122
|
+
methods.types.include?(schema.keys.first.to_s)
|
123
|
+
end
|
124
|
+
elsif OasRails.config.authenticate_all_routes_by_default
|
125
|
+
OasRails.config.security_schemas.keys.map { |key| { key => [] } }
|
126
|
+
else
|
127
|
+
[]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
115
131
|
def external_docs; end
|
116
132
|
end
|
117
133
|
end
|
@@ -15,28 +15,48 @@ module OasRails
|
|
15
15
|
{}
|
16
16
|
end
|
17
17
|
|
18
|
+
# Create the Base of the OAS hash.
|
19
|
+
# @see https://spec.openapis.org/oas/latest.html#schema
|
18
20
|
def base_spec
|
19
21
|
{
|
20
22
|
openapi: '3.1.0',
|
21
23
|
info: OasRails.config.info.to_spec,
|
22
24
|
servers: OasRails.config.servers.map(&:to_spec),
|
23
|
-
paths
|
24
|
-
components
|
25
|
-
security
|
25
|
+
paths:,
|
26
|
+
components:,
|
27
|
+
security:,
|
26
28
|
tags: OasRails.config.tags.map(&:to_spec),
|
27
29
|
externalDocs: {}
|
28
30
|
}
|
29
31
|
end
|
30
32
|
|
31
|
-
|
33
|
+
# Create the Security Requirement Object.
|
34
|
+
# @see https://spec.openapis.org/oas/latest.html#security-requirement-object
|
35
|
+
def security
|
36
|
+
return [] unless OasRails.config.authenticate_all_routes_by_default
|
37
|
+
|
38
|
+
OasRails.config.security_schemas.map { |key, _| { key => [] } }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Create the Paths Object For the Root of the OAS.
|
42
|
+
# @see https://spec.openapis.org/oas/latest.html#paths-object
|
43
|
+
def paths
|
32
44
|
Paths.from_string_paths(string_paths: RouteExtractor.host_paths).to_spec
|
33
45
|
end
|
34
46
|
|
35
|
-
|
47
|
+
# Created the Components Object For the Root of the OAS.
|
48
|
+
# @see https://spec.openapis.org/oas/latest.html#components-object
|
49
|
+
def components
|
36
50
|
{
|
37
|
-
schemas: {}, parameters: {},
|
51
|
+
schemas: {}, parameters: {}, securitySchemes: security_schemas, requestBodies: {}, responses: {},
|
38
52
|
headers: {}, examples: {}, links: {}, callbacks: {}
|
39
53
|
}
|
40
54
|
end
|
55
|
+
|
56
|
+
# Create the Security Schemas Array inside components field of the OAS.
|
57
|
+
# @see https://spec.openapis.org/oas/latest.html#security-scheme-object
|
58
|
+
def security_schemas
|
59
|
+
OasRails.config.security_schemas
|
60
|
+
end
|
41
61
|
end
|
42
62
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module OasRails
|
2
|
+
module Utils
|
3
|
+
TYPE_MAPPING = {
|
4
|
+
'String' => 'string',
|
5
|
+
'Integer' => 'number',
|
6
|
+
'Float' => 'number',
|
7
|
+
'TrueClass' => 'boolean',
|
8
|
+
'FalseClass' => 'boolean',
|
9
|
+
'Boolean' => 'boolean',
|
10
|
+
'NilClass' => 'null',
|
11
|
+
'Hash' => 'object',
|
12
|
+
'Object' => 'object',
|
13
|
+
'DateTime' => 'string'
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
class << self
|
17
|
+
# Method for detect test framework of the Rails App
|
18
|
+
# It is used for generate examples in operations
|
19
|
+
def detect_test_framework
|
20
|
+
if defined?(FactoryBot)
|
21
|
+
:factory_bot
|
22
|
+
elsif ActiveRecord::Base.connection.table_exists?('ar_internal_metadata')
|
23
|
+
:fixtures
|
24
|
+
else
|
25
|
+
:unknown
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def type_to_schema(type_string)
|
30
|
+
if type_string.start_with?('Array<')
|
31
|
+
inner_type = type_string[/Array<(.+)>$/, 1]
|
32
|
+
{
|
33
|
+
"type" => "array",
|
34
|
+
"items" => type_to_schema(inner_type)
|
35
|
+
}
|
36
|
+
else
|
37
|
+
{ "type" => TYPE_MAPPING.fetch(type_string, 'string') }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def hash_to_json_schema(hash)
|
42
|
+
{
|
43
|
+
type: 'object',
|
44
|
+
properties: hash_to_properties(hash),
|
45
|
+
required: []
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def hash_to_properties(hash)
|
50
|
+
hash.transform_values do |value|
|
51
|
+
if value.is_a?(Hash)
|
52
|
+
hash_to_json_schema(value)
|
53
|
+
elsif value.is_a?(Class)
|
54
|
+
{ type: ruby_type_to_json_type(value.name) }
|
55
|
+
else
|
56
|
+
{ type: ruby_type_to_json_type(value.class.name) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def ruby_type_to_json_type(ruby_type)
|
62
|
+
TYPE_MAPPING.fetch(ruby_type, 'string')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/oas_rails/version.rb
CHANGED
@@ -55,7 +55,7 @@ module OasRails
|
|
55
55
|
|
56
56
|
begin
|
57
57
|
hash = eval(hash_string)
|
58
|
-
hash =
|
58
|
+
hash = Utils.hash_to_json_schema(hash)
|
59
59
|
rescue StandardError
|
60
60
|
hash = {}
|
61
61
|
end
|
@@ -94,7 +94,7 @@ module OasRails
|
|
94
94
|
text = match[1].strip
|
95
95
|
name, location = parse_position_name(text)
|
96
96
|
type, required = parse_type(match[2].strip)
|
97
|
-
schema =
|
97
|
+
schema = Utils.type_to_schema(type)
|
98
98
|
|
99
99
|
ParameterTag.new(tag_name, name, match[3].strip, schema, location, required:)
|
100
100
|
else
|
@@ -109,7 +109,7 @@ module OasRails
|
|
109
109
|
|
110
110
|
begin
|
111
111
|
hash = parse_str_to_hash(match[3].strip)
|
112
|
-
hash =
|
112
|
+
hash = Utils.hash_to_json_schema(hash)
|
113
113
|
rescue StandardError
|
114
114
|
hash = {}
|
115
115
|
end
|