swagger_api 0.1.43

Sign up to get free protection for your applications and to get access to all the features.
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