swagger_api 0.1.43
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 +7 -0
- data/.codeclimate.yml +20 -0
- data/.gitignore +13 -0
- data/.gitlab-ci.yml +61 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +155 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/swagger_api.rb +123 -0
- data/lib/swagger_api/actions.rb +43 -0
- data/lib/swagger_api/column_schema.rb +41 -0
- data/lib/swagger_api/component_schema.rb +50 -0
- data/lib/swagger_api/components.rb +24 -0
- data/lib/swagger_api/concerns/columns.rb +24 -0
- data/lib/swagger_api/operations/base.rb +86 -0
- data/lib/swagger_api/operations/create.rb +39 -0
- data/lib/swagger_api/operations/delete.rb +20 -0
- data/lib/swagger_api/operations/index.rb +50 -0
- data/lib/swagger_api/operations/show.rb +11 -0
- data/lib/swagger_api/operations/update.rb +32 -0
- data/lib/swagger_api/paths.rb +52 -0
- data/lib/swagger_api/railtie.rb +6 -0
- data/lib/swagger_api/request_bodies.rb +28 -0
- data/lib/swagger_api/tasks/swagger.rake +13 -0
- data/lib/swagger_api/version.rb +3 -0
- data/swagger.yml +46 -0
- data/swagger_api.gemspec +38 -0
- metadata +162 -0
data/bin/setup
ADDED
data/lib/swagger_api.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'swagger_api/version'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module SwaggerApi
|
5
|
+
class Generator
|
6
|
+
def prettify
|
7
|
+
JSON.pretty_generate(JSON.parse(json))
|
8
|
+
end
|
9
|
+
|
10
|
+
def json
|
11
|
+
create.to_json
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
@config ||= {
|
16
|
+
openapi: '3.0.0',
|
17
|
+
security: [{api_key: []}],
|
18
|
+
info: info,
|
19
|
+
servers: [{url: server_url}],
|
20
|
+
paths: Paths.new(controllers: config.controllers).create,
|
21
|
+
components: {
|
22
|
+
responses: responses,
|
23
|
+
schemas: Components.new(controllers: config.controllers).create,
|
24
|
+
requestBodies: RequestBodies.new(controllers: config.controllers).create,
|
25
|
+
securitySchemes: security_schemes,
|
26
|
+
},
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def config
|
31
|
+
@yaml_config ||= JSON.parse(YAML.load_file("#{Rails.root.to_s}/config/swagger.yml").to_json, object_class: OpenStruct)
|
32
|
+
end
|
33
|
+
|
34
|
+
def security_schemes
|
35
|
+
{
|
36
|
+
api_key: {
|
37
|
+
type: 'apiKey',
|
38
|
+
name: 'Authorization',
|
39
|
+
in: 'header'
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def responses
|
45
|
+
@responses ||= custom_responses || default_responses
|
46
|
+
end
|
47
|
+
|
48
|
+
def custom_responses
|
49
|
+
custom_responses_path = "#{Rails.root.to_s}/config/swagger_custom_responses.json"
|
50
|
+
return unless File.exist?(custom_responses_path)
|
51
|
+
@custom_responses ||= JSON.parse(File.read(custom_responses_path), object_class: OpenStruct)
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_responses
|
55
|
+
{
|
56
|
+
NotFound: {
|
57
|
+
description: "The specified resource was not found",
|
58
|
+
content: {
|
59
|
+
'application/json; charset=utf-8' => {
|
60
|
+
schema: {
|
61
|
+
type: 'string',
|
62
|
+
example: 'Not Found'
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
},
|
67
|
+
Unauthorized: {
|
68
|
+
description: "Unauthorized",
|
69
|
+
content: {
|
70
|
+
'application/json; charset=utf-8' => {
|
71
|
+
schema: {
|
72
|
+
type: 'string',
|
73
|
+
example: 'Not Authorized'
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
},
|
78
|
+
BadRequest: {
|
79
|
+
description: "Bad Request",
|
80
|
+
content: {
|
81
|
+
'application/json; charset=utf-8' => {
|
82
|
+
schema: {
|
83
|
+
example: ['The field name is invalid.', 'The id must be present'],
|
84
|
+
type: 'array',
|
85
|
+
items: {
|
86
|
+
type: 'string'
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def info
|
96
|
+
{
|
97
|
+
version: config.info.version,
|
98
|
+
title: config.info.title,
|
99
|
+
description: config.info.description,
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def server_url
|
104
|
+
return unless config.server.respond_to?(Rails.env)
|
105
|
+
config.servers.send(Rails.env).url
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
require 'swagger_api/railtie'
|
110
|
+
|
111
|
+
require 'swagger_api/actions'
|
112
|
+
require 'swagger_api/concerns/columns'
|
113
|
+
require 'swagger_api/column_schema'
|
114
|
+
require 'swagger_api/component_schema'
|
115
|
+
require 'swagger_api/components'
|
116
|
+
require 'swagger_api/operations/base'
|
117
|
+
require 'swagger_api/operations/create'
|
118
|
+
require 'swagger_api/operations/delete'
|
119
|
+
require 'swagger_api/operations/index'
|
120
|
+
require 'swagger_api/operations/show'
|
121
|
+
require 'swagger_api/operations/update'
|
122
|
+
require 'swagger_api/paths'
|
123
|
+
require 'swagger_api/request_bodies'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_attr'
|
2
|
+
|
3
|
+
module SwaggerApi
|
4
|
+
class Actions
|
5
|
+
include ActiveAttr::Model
|
6
|
+
|
7
|
+
validate :validate_actions
|
8
|
+
attr_accessor :controller
|
9
|
+
|
10
|
+
|
11
|
+
def all!
|
12
|
+
raise self.errors.full_messages unless self.valid?
|
13
|
+
return only_actions unless only_actions.blank?
|
14
|
+
defined_actions
|
15
|
+
end
|
16
|
+
|
17
|
+
def defined_actions
|
18
|
+
(restful_actions + controller_actions) - except_actions
|
19
|
+
end
|
20
|
+
|
21
|
+
def controller_actions
|
22
|
+
return [] unless controller.actions.is_a? Array
|
23
|
+
controller.actions
|
24
|
+
end
|
25
|
+
|
26
|
+
def only_actions
|
27
|
+
controller.actions.try(:only) || []
|
28
|
+
end
|
29
|
+
|
30
|
+
def except_actions
|
31
|
+
controller.actions.try(:except) || []
|
32
|
+
end
|
33
|
+
|
34
|
+
def restful_actions
|
35
|
+
%w(index show create update delete)
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_actions
|
39
|
+
errors.add(:base, "`actions` must include at least one of #{restful_actions}") if restful_actions.blank?
|
40
|
+
errors.add(:base, "`actions` can only include one of #{restful_actions}. #{(defined_actions - restful_actions)} are not allowed") unless (defined_actions - restful_actions).blank?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SwaggerApi
|
2
|
+
class ColumnSchema
|
3
|
+
include ActiveAttr::Model
|
4
|
+
attr_accessor :column
|
5
|
+
|
6
|
+
def create
|
7
|
+
schema = {
|
8
|
+
type: type_from_column,
|
9
|
+
format: format_from_column
|
10
|
+
}
|
11
|
+
schema[:minimum] = 1 if column.type == :integer && column.name.to_s.ends_with?('id')
|
12
|
+
schema[:minimum] = 0 if column.type == :integer && !column.name.to_s.ends_with?('id')
|
13
|
+
schema
|
14
|
+
end
|
15
|
+
|
16
|
+
def type_from_column
|
17
|
+
if %i(datetime date time).include?(column.type)
|
18
|
+
:string
|
19
|
+
elsif %i(float double).include?(column.type)
|
20
|
+
:number
|
21
|
+
else
|
22
|
+
column.type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def format_from_column
|
27
|
+
case column.type
|
28
|
+
when :datetime
|
29
|
+
'date-time'
|
30
|
+
when :integer
|
31
|
+
:int64
|
32
|
+
else
|
33
|
+
if column.name.to_s == 'email'
|
34
|
+
:email
|
35
|
+
else
|
36
|
+
column.type
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SwaggerApi
|
2
|
+
class ComponentSchema
|
3
|
+
include ActiveAttr::Model
|
4
|
+
include Concerns::Columns
|
5
|
+
attr_accessor :controller
|
6
|
+
|
7
|
+
def create
|
8
|
+
{
|
9
|
+
required: required,
|
10
|
+
properties: properties,
|
11
|
+
type: 'object'
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def required
|
18
|
+
controller.try(:columns).try(:required) ||
|
19
|
+
columns.map(&:name) & clean_required_attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
def clean_required_attributes
|
23
|
+
required_attributes.map do |attribute|
|
24
|
+
if model.reflect_on_all_associations(:belongs_to).map(&:name).map(&:to_s).include?(attribute)
|
25
|
+
"#{attribute}_id"
|
26
|
+
else
|
27
|
+
attribute
|
28
|
+
end
|
29
|
+
end.compact.uniq.map(&:to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def required_attributes
|
33
|
+
model.validators.map do |validator|
|
34
|
+
validator.attributes if validator.is_a?(ActiveRecord::Validations::PresenceValidator)
|
35
|
+
end.compact.flatten.uniq.map(&:to_s)
|
36
|
+
end
|
37
|
+
|
38
|
+
def properties
|
39
|
+
properties = {}
|
40
|
+
columns.each do |column|
|
41
|
+
properties[column.name] = ColumnSchema.new(column: column).create
|
42
|
+
end
|
43
|
+
properties
|
44
|
+
end
|
45
|
+
|
46
|
+
def model
|
47
|
+
controller.model.constantize
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SwaggerApi
|
2
|
+
class Components
|
3
|
+
include ActiveAttr::Model
|
4
|
+
attr_accessor :controllers
|
5
|
+
|
6
|
+
def create
|
7
|
+
return @components unless @components.nil?
|
8
|
+
@components = {}
|
9
|
+
controllers.each do |controller|
|
10
|
+
if controller.custom_model_file.nil?
|
11
|
+
@components[controller.model] = ComponentSchema.new(controller: controller).create
|
12
|
+
else
|
13
|
+
@components.merge!(custom_json(controller.custom_model_file))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
@components
|
17
|
+
end
|
18
|
+
|
19
|
+
def custom_json(custom_model_file)
|
20
|
+
file = File.read(custom_model_file)
|
21
|
+
JSON.parse(file)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SwaggerApi
|
2
|
+
module Concerns
|
3
|
+
module Columns
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
def columns
|
8
|
+
if controller.columns.try(:only).present?
|
9
|
+
model.columns.select! do |column|
|
10
|
+
controller.columns.only.include?(column.name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
if controller.columns.try(:except).present?
|
15
|
+
model.columns.reject! do |column|
|
16
|
+
controller.columns.except.include?(column.name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
model.columns
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module SwaggerApi
|
2
|
+
module Operations
|
3
|
+
class Base
|
4
|
+
include ActiveAttr::Model
|
5
|
+
include SwaggerApi::Concerns::Columns
|
6
|
+
|
7
|
+
attr_accessor :controller, :action
|
8
|
+
|
9
|
+
def create
|
10
|
+
{
|
11
|
+
summary: "#{readable_action} #{model_name}",
|
12
|
+
description: "#{readable_action} #{model_name.downcase}'s information",
|
13
|
+
parameters: parameters,
|
14
|
+
responses: responses,
|
15
|
+
tags: [model_name],
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def parameters
|
20
|
+
[
|
21
|
+
{
|
22
|
+
name: 'id',
|
23
|
+
in: 'path',
|
24
|
+
description: "ID of #{model_name}",
|
25
|
+
required: true,
|
26
|
+
schema: {
|
27
|
+
type: :integer,
|
28
|
+
format: :int64,
|
29
|
+
minimum: 1
|
30
|
+
},
|
31
|
+
}
|
32
|
+
]
|
33
|
+
end
|
34
|
+
|
35
|
+
def responses
|
36
|
+
return @responses unless @responses.nil?
|
37
|
+
@responses = success_response
|
38
|
+
error_responses.each do |error_response|
|
39
|
+
@responses.merge!(error_response)
|
40
|
+
end
|
41
|
+
@responses
|
42
|
+
end
|
43
|
+
|
44
|
+
def success_response
|
45
|
+
{
|
46
|
+
'200' => {
|
47
|
+
description: "#{readable_action} #{model_name.downcase}'s information",
|
48
|
+
content: {
|
49
|
+
'application/json; charset=utf-8' => {
|
50
|
+
schema: {
|
51
|
+
'$ref' => "#/components/schemas/#{model_name}"
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def error_responses
|
60
|
+
[
|
61
|
+
{
|
62
|
+
'404' => { '$ref' => '#/components/responses/NotFound' }
|
63
|
+
},
|
64
|
+
{
|
65
|
+
'401' => { '$ref' => '#/components/responses/Unauthorized' }
|
66
|
+
},
|
67
|
+
{
|
68
|
+
'422' => { '$ref' => '#/components/responses/BadRequest' }
|
69
|
+
}
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
def readable_action
|
74
|
+
@readable_action ||= self.class.name.demodulize.downcase
|
75
|
+
end
|
76
|
+
|
77
|
+
def model_name
|
78
|
+
@model_name ||= controller.model
|
79
|
+
end
|
80
|
+
|
81
|
+
def model
|
82
|
+
@model ||= model_name.constantize
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SwaggerApi
|
2
|
+
module Operations
|
3
|
+
class Create < Base
|
4
|
+
def create
|
5
|
+
create = super
|
6
|
+
create[:requestBody] = request_body
|
7
|
+
create.delete(:parameters)
|
8
|
+
create
|
9
|
+
end
|
10
|
+
|
11
|
+
def request_body
|
12
|
+
{
|
13
|
+
"$ref" => "#/components/requestBodies/#{model_name}"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def success_response
|
18
|
+
{
|
19
|
+
'303' => {
|
20
|
+
description: "#{readable_action} #{model_name.downcase}'s information",
|
21
|
+
headers: {
|
22
|
+
Location: {
|
23
|
+
schema: {
|
24
|
+
type: :string
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def error_responses
|
33
|
+
super.reject do |error_response|
|
34
|
+
%w(404).include?(error_response.keys.first)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|