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.
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,4 +1,5 @@
1
1
  module OasRails
2
2
  class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
3
4
  end
4
5
  end
@@ -1,9 +1,12 @@
1
1
  module OasRails
2
2
  class OasRailsController < ApplicationController
3
- def index; end
4
-
5
- def oas
6
- render json: Specification.new.to_json, status: :ok
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 %>/oas" theme = "dark" text-color="#f9f9f9" show-header = 'false'> </rapi-doc>
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,4 +1,3 @@
1
1
  OasRails::Engine.routes.draw do
2
- root 'oas_rails#index'
3
- get '/oas', to: 'oas_rails#oas'
2
+ get '(.:format)', to: 'oas_rails#index'
4
3
  end
@@ -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
- # config.default_tags_from = :namespace # Could be: :namespace or :controller
47
- # config.autodiscover_request_body = true # Try to get request body for create and update methods based on the controller name.
48
- # config.autodiscover_responses = true # Looks for renders in your source code and try to generate the responses.
49
- # config.api_path = "/" # set this config if your api is in a different namespace other than /
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(**kwargs)
6
+ def initialize
7
7
  @info = Info.new
8
- @servers = kwargs[:servers] || default_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
@@ -21,7 +21,7 @@ module OasRails
21
21
  end
22
22
 
23
23
  def search_for_examples_in_tests(klass:)
24
- case OasRails.detect_test_framework
24
+ case Utils.detect_test_framework
25
25
  when :factory_bot
26
26
  {}
27
27
  # TODO: create examples with FactoryBot
@@ -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
@@ -59,7 +59,7 @@ module OasRails
59
59
  schema = {}
60
60
  begin
61
61
  schema = if content.start_with?('{')
62
- OasRails.hash_to_json_schema(parse_hash_structure(content))
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(".")
@@ -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
- new(method: oas_route.verb.downcase, summary:, operation_id:, tags:, description:, parameters:, request_body:, responses:)
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: paths_spec,
24
- components: components_spec,
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
- def paths_spec
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
- def components_spec
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: {}, securitySchemas: {}, requestBodies: {}, responses: {},
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
@@ -1,3 +1,3 @@
1
1
  module OasRails
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -55,7 +55,7 @@ module OasRails
55
55
 
56
56
  begin
57
57
  hash = eval(hash_string)
58
- hash = OasRails.hash_to_json_schema(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 = OasRails.type_to_schema(type)
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 = OasRails.hash_to_json_schema(hash)
112
+ hash = Utils.hash_to_json_schema(hash)
113
113
  rescue StandardError
114
114
  hash = {}
115
115
  end