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.
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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