jsonapi_swagger_helpers 0.1.5 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b9b3f968a4f5d28cdde96e82960634eb620f152
4
- data.tar.gz: a1a488145afdab452e203eca3301f02fb9c03e04
3
+ metadata.gz: 9a9dd06a7c8afca90ba9b3b340598a61ee7473d4
4
+ data.tar.gz: a4e56e637f81f4da21a6e784c9a4d2dae0b85953
5
5
  SHA512:
6
- metadata.gz: 85b70ab34c7a2e0dcdb0aab4aea2d9d62cdcd598772f5eb186837a9e3ab79d169024de4721fa0b4893b14e30472ec544d2e7ede0620225f88628a28703448a58
7
- data.tar.gz: 0b33c9e6fad54818f4fcf28a8bea33692d6a51a204f11e6caa2b6b5238133ce9d3f91ccfb946d023a4d50c505afed588f44f4ed1b4d4e269b60d83474e71d171
6
+ metadata.gz: 002f847d7f43fa3433932b72fab3e1efba37aafa120d2ba7332b9df78c9792a7e9075d5e30a6f56592d69c49a8ab5a213a03ad55463cce5db5040720d2896fd1
7
+ data.tar.gz: edc488adacd76b2281ad138410e37e3150fb380b889550ec171f8e0e90207e5dd917c81fb94f40335189d790f7a50f648f9865d517a68969e0f29841699e54de
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ swagger.json
11
+ npm-debug.log
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency 'swagger-blocks', '~> 1.3'
22
+ # TODO: above 0.4.2
23
+ spec.add_dependency 'jsonapi_spec_helpers', ['< 1']
22
24
 
23
25
  spec.add_development_dependency "bundler", "~> 1.12"
24
26
  spec.add_development_dependency "rake", "~> 10.0"
@@ -0,0 +1,10 @@
1
+ class JsonapiSwaggerHelpers::Configuration
2
+ def type_mapping
3
+ @type_mapping ||= {
4
+ string: [String],
5
+ integer: [Integer, Bignum],
6
+ float: [Float],
7
+ boolean: [TrueClass, FalseClass]
8
+ }
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ class JsonapiSwaggerHelpers::CreateAction
2
+ include JsonapiSwaggerHelpers::Writeable
3
+
4
+ def action_name
5
+ :create
6
+ end
7
+
8
+ def generate
9
+ _self = self
10
+
11
+ define_schema
12
+ @node.operation :post do
13
+ key :description, _self.description
14
+ key :operationId, _self.operation_id
15
+ key :tags, _self.all_tags
16
+
17
+ parameter do
18
+ key :name, :payload
19
+ key :in, :body
20
+
21
+ schema do
22
+ key :'$ref', :"#{_self.strong_resource.name}_create"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ class JsonapiSwaggerHelpers::DestroyAction
2
+ include JsonapiSwaggerHelpers::Writeable
3
+
4
+ def action_name
5
+ :destroy
6
+ end
7
+
8
+ def generate
9
+ _self = self
10
+
11
+ @node.operation :delete do
12
+ key :description, _self.description
13
+ key :operationId, _self.operation_id
14
+ key :tags, _self.tags
15
+
16
+ _self.util.id_in_url(self)
17
+ end
18
+ end
19
+ end
@@ -1,13 +1,32 @@
1
1
  module JsonapiSwaggerHelpers
2
2
  module DocsControllerMixin
3
3
  def self.included(klass)
4
+ # Save our controller so we can execute Swagger::Blocks code against it
5
+ JsonapiSwaggerHelpers.docs_controller = klass
6
+
7
+ # Add glue code
4
8
  klass.send(:include, Swagger::Blocks)
5
- klass.extend(ResourceMixin)
9
+ klass.extend(ResourceMixin) # jsonapi_resource DSL
10
+ klass.extend(ClassMethods) # for predefining payloads
11
+
12
+ # Predefine swagger definitions for later reference
13
+ # * spec payloads define outputs
14
+ # * strong resources define inputs
15
+ klass.register_payload_definitions!
16
+ end
17
+
18
+ module ClassMethods
19
+ def register_payload_definitions!
20
+ JsonapiSpecHelpers.load_payloads!
21
+ JsonapiSpecHelpers::Payload.registry.each_pair do |payload_name, payload|
22
+ JsonapiSwaggerHelpers::PayloadDefinition.new(payload).generate
23
+ end
24
+ end
6
25
  end
7
26
 
27
+ # Give Swagger::Blocks what it wants
8
28
  def index
9
- klasses = [self.class, JsonapiSwaggerHelpers::StrongResourceMixin::Schemas]
10
- render json: Swagger::Blocks.build_root_json(klasses)
29
+ render json: Swagger::Blocks.build_root_json([self.class])
11
30
  end
12
31
  end
13
32
  end
@@ -0,0 +1,45 @@
1
+ class JsonapiSwaggerHelpers::IndexAction
2
+ include JsonapiSwaggerHelpers::Readable
3
+
4
+ def action_name
5
+ :index
6
+ end
7
+
8
+ def generate
9
+ _self = self
10
+
11
+ @node.operation :get do
12
+ key :description, _self.full_description
13
+ key :operationId, _self.operation_id
14
+ key :tags, _self.all_tags
15
+
16
+ _self.util.jsonapi_sorting(self)
17
+ _self.util.jsonapi_pagination(self)
18
+
19
+ _self.util.each_filter(_self.resource) do |filter_label|
20
+ _self.util.jsonapi_filter(self, filter_label)
21
+ end
22
+
23
+ _self.each_stat do |stat_name, calculations|
24
+ _self.util.jsonapi_stat(self, stat_name, calculations)
25
+ end
26
+
27
+ _self.util.jsonapi_fields(self, _self.jsonapi_type)
28
+
29
+ if _self.has_extra_fields?
30
+ _self.util.jsonapi_extra_fields(self, _self.resource)
31
+ end
32
+
33
+ if _self.has_sideloads?
34
+ _self.util.jsonapi_includes(self)
35
+
36
+ _self.each_association do |association_name, association_resource|
37
+ _self.util.each_filter(association_resource, association_name) do |filter_label|
38
+ _self.util.jsonapi_filter(self, filter_label)
39
+ _self.util.jsonapi_fields(self, association_resource.config[:type])
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,57 @@
1
+ class JsonapiSwaggerHelpers::PayloadDefinition
2
+ attr_reader :payload
3
+
4
+ # Given a spec payload like:
5
+ #
6
+ # key(:name, String)
7
+ #
8
+ # Return the corresponding swagger type, ie :string
9
+ # If a key has multiple types, we'll pick the first swagger type that matches:
10
+ #
11
+ # key(:total, [String, Integer]) => :string
12
+ def self.swagger_type_for(payload_name, attribute, type)
13
+ types = Array(type)
14
+ return :string if types.empty?
15
+
16
+ type_mapping.each_pair do |swagger_type, klasses|
17
+ if types.any? { |t| klasses.include?(t) }
18
+ return swagger_type
19
+ end
20
+ end
21
+
22
+ raise JsonapiSwaggerHelpers::Errors::TypeNotFound
23
+ .new(payload_name, attribute)
24
+ end
25
+
26
+ def self.type_mapping
27
+ JsonapiSwaggerHelpers.config.type_mapping
28
+ end
29
+
30
+ def initialize(payload)
31
+ @payload = payload
32
+ end
33
+
34
+ def context
35
+ JsonapiSwaggerHelpers.docs_controller
36
+ end
37
+
38
+ def jsonapi_type
39
+ payload.type
40
+ end
41
+
42
+ def generate
43
+ _self = self
44
+
45
+ context.send(:swagger_schema, payload.name) do
46
+ payload = _self.payload
47
+
48
+ payload.keys.each_pair do |attribute, config|
49
+ property attribute do
50
+ type = _self.class.swagger_type_for(payload.name, attribute, config[:type])
51
+ key :type, type
52
+ key :description, config[:description]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,83 @@
1
+ module JsonapiSwaggerHelpers::Readable
2
+ def self.included(klass)
3
+ klass.class_eval do
4
+ attr_reader :node,
5
+ :controller,
6
+ :resource,
7
+ :description,
8
+ :tags
9
+ end
10
+ end
11
+
12
+ def initialize(node, controller, description: nil, tags: [])
13
+ @node = node
14
+ @controller = controller
15
+ @resource = controller._jsonapi_compliable
16
+ @description = description || default_description
17
+ @tags = tags
18
+ end
19
+
20
+ def default_description
21
+ "#{action_name.capitalize} Action"
22
+ end
23
+
24
+ def operation_id
25
+ "#{controller.name.gsub('::', '-')}-#{action_name}"
26
+ end
27
+
28
+ def util
29
+ JsonapiSwaggerHelpers::Util
30
+ end
31
+
32
+ def include_directive
33
+ util.include_directive_for(controller, action_name)
34
+ end
35
+
36
+ def has_sideloads?
37
+ include_directive.keys.length > 0
38
+ end
39
+
40
+ def has_extra_fields?
41
+ resource.config[:extra_fields].keys.length > 1
42
+ end
43
+
44
+ def full_description
45
+ "#{description}<br /><br />#{util.sideload_label(include_directive)}"
46
+ end
47
+
48
+ def all_tags
49
+ tags + payload_tags
50
+ end
51
+
52
+ def payload_tags
53
+ util.payload_tags_for(resource, include_directive.to_hash)
54
+ end
55
+
56
+ def operation_id
57
+ "#{controller.name.gsub('::', '-')}-#{action_name}"
58
+ end
59
+
60
+ def each_stat
61
+ resource.config[:stats].each_pair do |stat_name, opts|
62
+ calculations = opts.calculations.keys - [:keys]
63
+ calculations = calculations.join(', ')
64
+
65
+ yield stat_name, calculations
66
+ end
67
+ end
68
+
69
+ def each_association
70
+ resource_map = util.all_resources(resource, include_directive)
71
+ resource_map.each_pair do |association_name, association_resource|
72
+ yield association_name, association_resource
73
+ end
74
+ end
75
+
76
+ def jsonapi_type
77
+ resource.config[:type]
78
+ end
79
+
80
+ def generate
81
+ raise 'override me'
82
+ end
83
+ end
@@ -1,76 +1,58 @@
1
1
  module JsonapiSwaggerHelpers
2
2
  module ResourceMixin
3
3
 
4
- def jsonapi_resource(base_path, tags: [], descriptions: {}, only: [], except: [])
5
- actions = [:index, :show, :create, :update, :destroy]
6
-
7
- unless only.empty?
8
- actions.select! { |a| only.include?(a) }
9
- end
10
-
11
- unless except.empty?
12
- actions.reject! { |a| except.include?(a) }
13
- end
4
+ def jsonapi_resource(base_path,
5
+ tags: [],
6
+ descriptions: {},
7
+ only: [],
8
+ except: [])
9
+ actions = [:index, :show, :create, :update, :destroy]
10
+ actions.select! { |a| only.include?(a) } unless only.empty?
11
+ actions.reject! { |a| except.include?(a) } unless except.empty?
14
12
 
15
13
  prefix = @swagger_root_node.data[:basePath]
16
14
  full_path = [prefix, base_path].join('/').gsub('//', '/')
17
- controller = controller_for(full_path)
15
+ controller = JsonapiSwaggerHelpers::Util.controller_for(full_path)
18
16
 
17
+ ctx = self
19
18
  if [:create, :index].any? { |a| actions.include?(a) }
20
19
  swagger_path base_path do
21
- if actions.include?(:index)
22
- operation :get do
23
- key :tags, tags
24
- key :description, descriptions[:index]
25
- jsonapi_index(controller)
26
- end
20
+ if actions.include?(:index) && controller.action_methods.include?('index')
21
+ index_action = JsonapiSwaggerHelpers::IndexAction.new \
22
+ self, controller, tags: tags, description: descriptions[:index]
23
+ index_action.generate
27
24
  end
28
25
 
29
- if actions.include?(:create)
30
- operation :post do
31
- key :tags, tags
32
- key :description, descriptions[:create]
33
- strong_resource(controller, :create)
34
- end
26
+ if actions.include?(:create) && controller.action_methods.include?('create')
27
+ create_action = JsonapiSwaggerHelpers::CreateAction.new \
28
+ self, controller, tags: tags, description: descriptions[:create]
29
+ create_action.generate
35
30
  end
36
31
  end
37
32
  end
38
33
 
39
34
  if [:show, :update, :destroy].any? { |a| actions.include?(a) }
35
+ ctx = self
40
36
  swagger_path "#{base_path}/{id}" do
41
- if actions.include?(:show)
42
- operation :get do
43
- key :tags, tags
44
- key :description, descriptions[:show]
45
- jsonapi_show(controller)
46
- end
37
+ if actions.include?(:show) && controller.action_methods.include?('show')
38
+ show_action = JsonapiSwaggerHelpers::ShowAction.new \
39
+ self, controller, tags: tags, description: descriptions[:show]
40
+ show_action.generate
47
41
  end
48
42
 
49
- if actions.include?(:update)
50
- operation :put do
51
- key :tags, tags
52
- key :description, descriptions[:update]
53
- id_in_url
54
- strong_resource(controller, :update)
55
- end
43
+ if actions.include?(:update) && controller.action_methods.include?('update')
44
+ update_action = JsonapiSwaggerHelpers::UpdateAction.new \
45
+ self, controller, tags: tags, description: descriptions[:update]
46
+ update_action.generate
56
47
  end
57
48
 
58
- if actions.include?(:destroy)
59
- operation :delete do
60
- key :tags, tags
61
- key :description, descriptions[:destroy]
62
- id_in_url
63
- end
49
+ if actions.include?(:destroy) && controller.action_methods.include?('destroy')
50
+ destroy_action = JsonapiSwaggerHelpers::DestroyAction.new \
51
+ self, controller, tags: tags, description: descriptions[:destroy]
52
+ destroy_action.generate
64
53
  end
65
54
  end
66
55
  end
67
56
  end
68
-
69
- def controller_for(path)
70
- path = path.sub('{id}', '1')
71
- route = Rails.application.routes.recognize_path(path)
72
- "#{route[:controller]}_controller".classify.constantize
73
- end
74
-
75
57
  end
76
58
  end
@@ -0,0 +1,43 @@
1
+ class JsonapiSwaggerHelpers::ShowAction
2
+ include JsonapiSwaggerHelpers::Readable
3
+
4
+ def action_name
5
+ :show
6
+ end
7
+
8
+ def generate
9
+ _self = self
10
+
11
+ @node.operation :get do
12
+ key :description, _self.full_description
13
+ key :operationId, _self.operation_id
14
+ key :tags, _self.all_tags
15
+
16
+ _self.util.id_in_url(self)
17
+ _self.util.jsonapi_fields(self, _self.jsonapi_type)
18
+
19
+ if _self.has_extra_fields?
20
+ _self.util.jsonapi_extra_fields(self, _self.resource)
21
+ end
22
+
23
+ _self.each_stat do |stat_name, calculations|
24
+ _self.util.jsonapi_stat(self, stat_name, calculations)
25
+ end
26
+
27
+ if _self.has_sideloads?
28
+ _self.util.jsonapi_includes(self)
29
+
30
+ _self.each_association do |association_name, association_resource|
31
+ _self.util.each_filter(association_resource, association_name) do |filter_label|
32
+ _self.util.jsonapi_filter(self, filter_label)
33
+ _self.util.jsonapi_fields(self, association_resource.config[:type])
34
+
35
+ if association_resource.config[:extra_fields].keys.length > 0
36
+ _self.util.jsonapi_extra_fields(self, association_resource)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ class JsonapiSwaggerHelpers::UpdateAction
2
+ include JsonapiSwaggerHelpers::Writeable
3
+
4
+ def action_name
5
+ :update
6
+ end
7
+
8
+ def generate
9
+ _self = self
10
+
11
+ define_schema
12
+ @node.operation :put do
13
+ key :description, _self.description
14
+ key :operationId, _self.operation_id
15
+ key :tags, _self.all_tags
16
+
17
+ _self.util.id_in_url(self)
18
+
19
+ parameter do
20
+ key :name, :payload
21
+ key :in, :body
22
+
23
+ schema do
24
+ key :'$ref', :"#{_self.strong_resource.name}_update"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,165 @@
1
+ module JsonapiSwaggerHelpers::Util
2
+ def self.controller_for(path)
3
+ path = path.sub('{id}', '1')
4
+ route = Rails.application.routes.recognize_path(path)
5
+ "#{route[:controller]}_controller".classify.constantize
6
+ end
7
+
8
+ def self.sideload_label(include_directive)
9
+ sideloads = include_directive.to_string.split(",").sort.join(",<br/>")
10
+
11
+ <<-HTML
12
+ <label>
13
+ Possible sideloads:
14
+ <span class="possible-sideloads">#{sideloads}</span>
15
+ </label>
16
+ HTML
17
+ end
18
+
19
+ def self.each_filter(resource, association_name = nil)
20
+ resource.config[:filters].each_pair do |filter_name, opts|
21
+ if association_name
22
+ yield "filter[#{association_name}][#{filter_name}]"
23
+ else
24
+ yield "filter[#{filter_name}]"
25
+ end
26
+ end
27
+ end
28
+
29
+ def self.all_resources(resource, include_directive, memo = {})
30
+ resource.sideloading.sideloads.each_pair do |name, sideload|
31
+ next if memo[name] || !include_directive.key?(name)
32
+
33
+ memo[name] = sideload.resource.class
34
+ all_resources(sideload.resource.class, include_directive[name], memo)
35
+ end
36
+ memo
37
+ end
38
+
39
+ def self.include_directive_for(controller, action)
40
+ resource_class = controller._jsonapi_compliable
41
+ includes = resource_class.sideloading.to_hash[:base]
42
+ whitelist = resource_class.config[:sideload_whitelist]
43
+
44
+ if whitelist && whitelist[action]
45
+ includes = JsonapiCompliable::Util::IncludeParams
46
+ .scrub(includes, whitelist[action])
47
+ end
48
+
49
+ JSONAPI::IncludeDirective.new(includes)
50
+ end
51
+
52
+ def self.payloads_for(resource, include_hash)
53
+ [].tap do |payloads|
54
+ payloads << JsonapiSpecHelpers::Payload.by_type(resource.config[:type])
55
+
56
+ include_hash.each_pair do |name, nested|
57
+ sideload = resource.sideloading.sideloads[name]
58
+
59
+ if sideload.polymorphic?
60
+ sideload.polymorphic_groups.each_pair do |type, sl|
61
+ payloads << payloads_for(sl.resource_class, nested)
62
+ end
63
+ else
64
+ sideload_resource = sideload.resource_class
65
+ payloads << payloads_for(sideload_resource, nested)
66
+ end
67
+ end
68
+ end.flatten.uniq(&:name)
69
+ end
70
+
71
+ def self.payload_tags_for(resource, include_hash)
72
+ payloads_for(resource, include_hash).map { |p| "payload-#{p.name}" }
73
+ end
74
+
75
+ def self.jsonapi_filter(node, label)
76
+ node.parameter do
77
+ key :description, '<a href="http://jsonapi.org/format/#fetching-filtering">JSONAPI Filter</a>'
78
+ key :name, label
79
+ key :in, :query
80
+ key :type, :string
81
+ key :required, false
82
+ end
83
+ end
84
+
85
+ def self.jsonapi_sorting(node)
86
+ node.parameter do
87
+ key :description, '<a href="http://jsonapi.org/format/#fetching-sorting">JSONAPI Sorting</a>'
88
+ key :name, :sort
89
+ key :in, :query
90
+ key :type, :string
91
+ key :required, false
92
+ end
93
+ end
94
+
95
+ def self.jsonapi_pagination(node)
96
+ node.parameter do
97
+ key :description, '<a href="http://jsonapi.org/format/#fetching-pagination">JSONAPI Page Size</a>'
98
+ key :name, "page[size]"
99
+ key :in, :query
100
+ key :type, :string
101
+ key :required, false
102
+ end
103
+
104
+ node.parameter do
105
+ key :description, '<a href="http://jsonapi.org/format/#fetching-pagination">JSONAPI Page Number</a>'
106
+ key :name, "page[number]"
107
+ key :in, :query
108
+ key :type, :string
109
+ key :required, false
110
+ end
111
+ end
112
+
113
+ def self.jsonapi_stat(node, name, calculations)
114
+ node.parameter do
115
+ key :name, "stats[#{name}]"
116
+ key :description, "<a href=\"https://jsonapi-suite.github.io/jsonapi_suite/how-to-return-statistics\">JSONAPI Stats</a><br /><b>Possible Calculations:</b> #{calculations}"
117
+ key :in, :query
118
+ key :type, :string
119
+ key :required, false
120
+ end
121
+ end
122
+
123
+ def self.jsonapi_includes(node)
124
+ node.parameter do
125
+ key :description, '<a href="http://jsonapi.org/format/#fetching-includes">JSONAPI Includes</a>'
126
+ key :name, :include
127
+ key :in, :query
128
+ key :type, :string
129
+ key :required, false
130
+ end
131
+ end
132
+
133
+ def self.jsonapi_fields(node, jsonapi_type)
134
+ node.parameter do
135
+ key :description, '<a href="http://jsonapi.org/format/#fetching-sparse-fieldsets">JSONAPI Sparse Fieldset</a>'
136
+ key :name, "fields[#{jsonapi_type}]"
137
+ key :in, :query
138
+ key :type, :string
139
+ key :required, false
140
+ end
141
+ end
142
+
143
+ def self.jsonapi_extra_fields(node, resource)
144
+ jsonapi_type = resource.config[:type]
145
+
146
+ extra_field_names = resource.config[:extra_fields].keys.join(',')
147
+ node.parameter do
148
+ key :description, "<a href=\"https://jsonapi-suite.github.io/jsonapi_suite/how-to-conditionally-render-fields\">JSONAPI Extra Fields</a><br /><b>Possible Fields:</b> #{extra_field_names}"
149
+ key :name, "extra_fields[#{jsonapi_type}]"
150
+ key :in, :query
151
+ key :type, :string
152
+ key :required, false
153
+ end
154
+ end
155
+
156
+ def self.id_in_url(node)
157
+ node.parameter do
158
+ key :name, :id
159
+ key :in, :path
160
+ key :type, :string
161
+ key :required, true
162
+ key :description, 'record id'
163
+ end
164
+ end
165
+ end
@@ -1,3 +1,3 @@
1
1
  module JsonapiSwaggerHelpers
2
- VERSION = "0.1.5"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,89 @@
1
+ module JsonapiSwaggerHelpers::Writeable
2
+ def self.included(klass)
3
+ klass.class_eval do
4
+ attr_reader :node,
5
+ :controller,
6
+ :resource,
7
+ :description,
8
+ :tags
9
+ end
10
+ end
11
+
12
+ def initialize(node, controller, description: nil, tags: [])
13
+ @node = node
14
+ @controller = controller
15
+ @resource = controller._jsonapi_compliable
16
+ @description = description || default_description
17
+ @tags = tags
18
+ end
19
+
20
+ def util
21
+ JsonapiSwaggerHelpers::Util
22
+ end
23
+
24
+ def action_name
25
+ raise 'override me'
26
+ end
27
+
28
+ def default_description
29
+ "#{action_name.to_s.capitalize} Action"
30
+ end
31
+
32
+ def operation_id
33
+ "#{controller.name.gsub('::', '-')}-#{action_name}"
34
+ end
35
+
36
+ def all_tags
37
+ tags + payload_tags
38
+ end
39
+
40
+ def payload_tags
41
+ tags = [:"payload-#{strong_resource.name}_#{action_name}"]
42
+
43
+ strong_resource.relations.each_pair do |relation_name, relation_config|
44
+ tags << :"payload-#{strong_resource.name}_#{relation_name}_#{action_name}"
45
+ end
46
+
47
+ tags
48
+ end
49
+
50
+ def context
51
+ JsonapiSwaggerHelpers.docs_controller
52
+ end
53
+
54
+ def strong_resource
55
+ controller._strong_resources[action_name]
56
+ end
57
+
58
+ def define_schema
59
+ _self = self
60
+ context.send(:swagger_schema, :"#{strong_resource.name}_#{action_name}") do
61
+ _self.strong_resource.attributes.each_pair do |attribute, config|
62
+ property attribute do
63
+ key :type, config[:type] # TODO - swagger type?
64
+ end
65
+ end
66
+ end
67
+
68
+ _self.strong_resource.relations.each_pair do |relation_name, relation_config|
69
+ context.send(:swagger_schema, :"#{strong_resource.name}_#{relation_name}_#{action_name}") do
70
+ relation_config[:resource].attributes.each_pair do |attribute, config|
71
+ property attribute do
72
+ key :type, config[:type] # TODO - swagger type?
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def generate
80
+ _self = self
81
+
82
+ define_schema
83
+ @node.operation :post do
84
+ key :description, _self.description
85
+ key :operationId, _self.operation_id
86
+ key :tags, _self.all_tags
87
+ end
88
+ end
89
+ end
@@ -1,13 +1,26 @@
1
1
  require 'swagger/blocks'
2
- require "jsonapi_swagger_helpers/version"
3
- require "jsonapi_swagger_helpers/schema_helpers"
4
- require "jsonapi_swagger_helpers/strong_resource_mixin"
2
+ require "jsonapi_spec_helpers"
3
+ require "jsonapi_swagger_helpers/configuration"
4
+ require "jsonapi_swagger_helpers/payload_definition"
5
+ require "jsonapi_swagger_helpers/util"
6
+ require "jsonapi_swagger_helpers/readable"
7
+ require "jsonapi_swagger_helpers/writeable"
8
+ require "jsonapi_swagger_helpers/index_action"
9
+ require "jsonapi_swagger_helpers/show_action"
10
+ require "jsonapi_swagger_helpers/create_action"
11
+ require "jsonapi_swagger_helpers/update_action"
12
+ require "jsonapi_swagger_helpers/destroy_action"
13
+
5
14
  require "jsonapi_swagger_helpers/resource_mixin"
6
15
  require "jsonapi_swagger_helpers/docs_controller_mixin"
7
16
 
8
17
  module JsonapiSwaggerHelpers
9
- def self.prepended(klass)
10
- klass.send(:include, StrongResourceMixin)
18
+ def self.configure
19
+ yield config
20
+ end
21
+
22
+ def self.config
23
+ @config ||= Configuration.new
11
24
  end
12
25
 
13
26
  def self.docs_controller
@@ -17,125 +30,6 @@ module JsonapiSwaggerHelpers
17
30
  def self.docs_controller=(controller)
18
31
  @docs_controller = controller
19
32
  end
20
-
21
- def jsonapi_link
22
- "<br/><p><a href='http://jsonapi.org'>JSONAPI-compliant</a> endpoint.</p><br />"
23
- end
24
-
25
- def validation_messages(messages)
26
- string = "<p><b>Validations:</b><ul>"
27
- messages.each do |message|
28
- string << "<li>#{message}</li>"
29
- end
30
- string << "</ul></p>"
31
- end
32
-
33
- def jsonapi_index(controller)
34
- jsonapi_includes(controller, :index)
35
- jsonapi_filters(controller)
36
- jsonapi_stats(controller)
37
- jsonapi_pagination
38
- jsonapi_sorting
39
- end
40
-
41
- def jsonapi_show(controller)
42
- id_in_url
43
- jsonapi_includes(controller, :show)
44
- end
45
-
46
- def id_in_url
47
- parameter do
48
- key :name, :id
49
- key :in, :path
50
- key :type, :string
51
- key :required, true
52
- key :description, 'record id'
53
- end
54
- end
55
-
56
- def jsonapi_filters(controller)
57
- filter_names = []
58
- controller._jsonapi_compliable.filters.each_pair do |name, opts|
59
- filter_names << name
60
- end
61
-
62
- filter_names.each do |filter_name|
63
- parameter do
64
- key :name, "filter[#{filter_name}]"
65
- key :in, :query
66
- key :type, :string
67
- key :required, false
68
- key :description, "<a href='http://jsonapi.org/format/#fetching-filtering'>JSONAPI filter</a>"
69
-
70
- items do
71
- key :model, :string
72
- end
73
- end
74
- end
75
- end
76
-
77
- def jsonapi_stats(controller)
78
- controller._jsonapi_compliable.stats.each_pair do |stat_name, opts|
79
- calculations = opts.calculations.keys - [:keys]
80
- calculations = calculations.join('<br/>')
81
- parameter do
82
- key :name, "stats[#{stat_name}]"
83
- key :in, :query
84
- key :type, :string
85
- key :required, false
86
- key :description, "<a href='http://jsonapi.org/format/#document-meta'>JSONAPI meta data</a><br/> #{calculations}"
87
-
88
- items do
89
- key :model, :string
90
- end
91
- end
92
- end
93
- end
94
-
95
- def jsonapi_pagination
96
- parameter do
97
- key :name, "page[size]"
98
- key :in, :query
99
- key :type, :string
100
- key :required, false
101
- key :description, "<a href='http://jsonapi.org/format/#fetching-pagination'>JSONAPI page size</a>"
102
- end
103
-
104
- parameter do
105
- key :name, "page[number]"
106
- key :in, :query
107
- key :type, :string
108
- key :required, false
109
- key :description, "<a href='http://jsonapi.org/format/#fetching-pagination'>JSONAPI page number</a>"
110
- end
111
- end
112
-
113
- def jsonapi_sorting
114
- parameter do
115
- key :name, :sort
116
- key :in, :query
117
- key :type, :string
118
- key :required, false
119
- key :description, "<a href='http://jsonapi.org/format/#fetching-sorting'>JSONAPI sort</a>"
120
- end
121
- end
122
-
123
- def jsonapi_includes(controller, action)
124
- includes = controller._jsonapi_compliable.sideloads[:whitelist]
125
-
126
- if includes && includes[action]
127
- directive = includes[action]
128
- includes = directive.to_string.split(",").sort.join(",<br/>")
129
-
130
- parameter do
131
- key :name, :include
132
- key :in, :query
133
- key :type, :string
134
- key :required, false
135
- key :description, "<a href='http://jsonapi.org/format/#fetching-includes'>JSONAPI includes</a>: <br/> #{includes}"
136
- end
137
- end
138
- end
139
33
  end
140
34
 
141
35
  Swagger::Blocks::OperationNode.prepend(JsonapiSwaggerHelpers)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi_swagger_helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-26 00:00:00.000000000 Z
11
+ date: 2017-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: swagger-blocks
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jsonapi_spec_helpers
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "<"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -84,11 +98,19 @@ files:
84
98
  - bin/setup
85
99
  - jsonapi_swagger_helpers.gemspec
86
100
  - lib/jsonapi_swagger_helpers.rb
101
+ - lib/jsonapi_swagger_helpers/configuration.rb
102
+ - lib/jsonapi_swagger_helpers/create_action.rb
103
+ - lib/jsonapi_swagger_helpers/destroy_action.rb
87
104
  - lib/jsonapi_swagger_helpers/docs_controller_mixin.rb
105
+ - lib/jsonapi_swagger_helpers/index_action.rb
106
+ - lib/jsonapi_swagger_helpers/payload_definition.rb
107
+ - lib/jsonapi_swagger_helpers/readable.rb
88
108
  - lib/jsonapi_swagger_helpers/resource_mixin.rb
89
- - lib/jsonapi_swagger_helpers/schema_helpers.rb
90
- - lib/jsonapi_swagger_helpers/strong_resource_mixin.rb
109
+ - lib/jsonapi_swagger_helpers/show_action.rb
110
+ - lib/jsonapi_swagger_helpers/update_action.rb
111
+ - lib/jsonapi_swagger_helpers/util.rb
91
112
  - lib/jsonapi_swagger_helpers/version.rb
113
+ - lib/jsonapi_swagger_helpers/writeable.rb
92
114
  homepage:
93
115
  licenses:
94
116
  - MIT
@@ -109,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
131
  version: '0'
110
132
  requirements: []
111
133
  rubyforge_project:
112
- rubygems_version: 2.5.1
134
+ rubygems_version: 2.6.11
113
135
  signing_key:
114
136
  specification_version: 4
115
137
  summary: Swagger helpers for jsonapi.org-compatible APIs
@@ -1,78 +0,0 @@
1
- module JsonapiSwaggerHelpers
2
- class SchemaHelpers
3
- def self.attributes_schema
4
- lambda do |attributes|
5
- property :attributes do
6
- key :type, :object
7
-
8
- attributes.each_pair do |name, attr_type|
9
- property name do
10
- key :name, name
11
- key :type, attr_type
12
- end
13
- end
14
- end
15
- end
16
- end
17
-
18
- def self.relationships_schema
19
- lambda do |relationships|
20
- property :relationships do
21
- key :type, :object
22
-
23
- relationships.each_pair do |relation_name, opts|
24
- property relation_name do
25
- property :data do
26
- if opts[:array]
27
- key :type, :array
28
- items do
29
- if opts[:id]
30
- property :id do
31
- key :type, :string
32
- end
33
- end
34
-
35
- property :type do
36
- key :type, :string
37
- key :required, true
38
- key :enum, [opts[:jsonapi_type]]
39
- end
40
-
41
- if opts[:attributes]
42
- instance_exec(opts[:attributes], &SchemaHelpers.attributes_schema)
43
- end
44
-
45
- if opts[:relationships]
46
- instance_exec(opts[:relationships], &SchemaHelpers.relationships_schema)
47
- end
48
- end
49
- else
50
- if opts[:id]
51
- property :id do
52
- key :type, :string
53
- end
54
- end
55
-
56
- property :type do
57
- key :type, :string
58
- key :required, true
59
- key :enum, [opts[:jsonapi_type]]
60
- end
61
-
62
- if opts[:attributes]
63
- instance_exec(opts[:attributes], &SchemaHelpers.attributes_schema)
64
- end
65
-
66
- if opts[:relationships]
67
- instance_exec(opts[:relationships], &SchemaHelpers.relationships_schema)
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end
75
- end
76
-
77
- end
78
- end
@@ -1,120 +0,0 @@
1
- module JsonapiSwaggerHelpers
2
- module StrongResourceMixin
3
-
4
- class Schemas
5
- include Swagger::Blocks
6
-
7
- def self.schema(name, &blk)
8
- swagger_schema(name, &blk)
9
- end
10
- end
11
-
12
- def strong_resource(controller, action)
13
- update = action == :update
14
- resource = controller._strong_resources[action]
15
- opts = { jsonapi_type: resource.jsonapi_type }
16
-
17
- if (attributes = strong_resource_attributes(resource, update)).present?
18
- opts[:attributes] = attributes
19
- end
20
-
21
- if (relationships = strong_resource_relationships(resource, update)).present?
22
- opts[:relationships] = relationships
23
- end
24
-
25
- jsonapi_payload(SecureRandom.uuid.to_sym, opts)
26
- end
27
-
28
- def strong_resource_attributes(resource, is_update = false)
29
- attributes = {}
30
- resource.attributes.each_pair do |name, opts|
31
- type = StrongResources.config.strong_params[opts[:type]][:swagger]
32
- attributes[name] = type
33
-
34
- if is_update
35
- if resource.destroy?
36
- attributes[:_destroy] = :boolean
37
- end
38
-
39
- if resource.delete?
40
- attributes[:_delete] = :boolean
41
- end
42
- end
43
- end
44
-
45
- attributes = attributes.slice(*resource.only) if !!resource.only
46
- attributes = attributes.except(*resource.except) if !!resource.except
47
- attributes
48
- end
49
-
50
- def strong_resource_relationships(resource, is_update = false)
51
- {}.tap do |relations|
52
- resource.relations.each_pair do |relation_name, opts|
53
- resource = opts[:resource]
54
-
55
- payload = {
56
- jsonapi_type: resource.jsonapi_type,
57
- id: true,
58
- array: resource.has_many?
59
- }
60
-
61
- if (attributes = strong_resource_attributes(resource, is_update)).present?
62
- payload[:attributes] = attributes
63
- end
64
-
65
- if (relationships = strong_resource_relationships(resource, is_update)).present?
66
- payload[:relationships] = relationships
67
- end
68
-
69
- relations[relation_name] = payload
70
- end
71
- end
72
- end
73
-
74
- def jsonapi_payload(schema_name, payload)
75
- jsonapi_input_schema(schema_name, payload)
76
-
77
- parameter do
78
- key :name, :payload
79
- key :in, :body
80
-
81
- schema do
82
- key :'$ref', schema_name
83
- end
84
- end
85
- end
86
-
87
- def jsonapi_input_schema(schema_name,
88
- id: false,
89
- jsonapi_type:,
90
- attributes: nil,
91
- relationships: nil)
92
- Schemas.schema(schema_name) do
93
- property :data do
94
- key :type, :object
95
-
96
- property :type do
97
- key :type, :string
98
- key :required, true
99
- key :enum, [jsonapi_type]
100
- end
101
-
102
- if id
103
- property :id do
104
- key :type, :string
105
- end
106
- end
107
-
108
- if attributes
109
- instance_exec(attributes, &SchemaHelpers.attributes_schema)
110
- end
111
-
112
- if relationships
113
- instance_exec(relationships, &SchemaHelpers.relationships_schema)
114
- end
115
- end
116
- end
117
- end
118
-
119
- end
120
- end