sanger-jsonapi-resources 0.1.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +53 -0
  4. data/lib/generators/jsonapi/USAGE +13 -0
  5. data/lib/generators/jsonapi/controller_generator.rb +14 -0
  6. data/lib/generators/jsonapi/resource_generator.rb +14 -0
  7. data/lib/generators/jsonapi/templates/jsonapi_controller.rb +4 -0
  8. data/lib/generators/jsonapi/templates/jsonapi_resource.rb +4 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +320 -0
  10. data/lib/jsonapi/cached_resource_fragment.rb +127 -0
  11. data/lib/jsonapi/callbacks.rb +51 -0
  12. data/lib/jsonapi/compiled_json.rb +36 -0
  13. data/lib/jsonapi/configuration.rb +258 -0
  14. data/lib/jsonapi/error.rb +47 -0
  15. data/lib/jsonapi/error_codes.rb +60 -0
  16. data/lib/jsonapi/exceptions.rb +563 -0
  17. data/lib/jsonapi/formatter.rb +169 -0
  18. data/lib/jsonapi/include_directives.rb +100 -0
  19. data/lib/jsonapi/link_builder.rb +152 -0
  20. data/lib/jsonapi/mime_types.rb +41 -0
  21. data/lib/jsonapi/naive_cache.rb +30 -0
  22. data/lib/jsonapi/operation.rb +24 -0
  23. data/lib/jsonapi/operation_dispatcher.rb +88 -0
  24. data/lib/jsonapi/operation_result.rb +65 -0
  25. data/lib/jsonapi/operation_results.rb +35 -0
  26. data/lib/jsonapi/paginator.rb +209 -0
  27. data/lib/jsonapi/processor.rb +328 -0
  28. data/lib/jsonapi/relationship.rb +94 -0
  29. data/lib/jsonapi/relationship_builder.rb +167 -0
  30. data/lib/jsonapi/request_parser.rb +678 -0
  31. data/lib/jsonapi/resource.rb +1255 -0
  32. data/lib/jsonapi/resource_controller.rb +5 -0
  33. data/lib/jsonapi/resource_controller_metal.rb +16 -0
  34. data/lib/jsonapi/resource_serializer.rb +531 -0
  35. data/lib/jsonapi/resources/version.rb +5 -0
  36. data/lib/jsonapi/response_document.rb +135 -0
  37. data/lib/jsonapi/routing_ext.rb +262 -0
  38. data/lib/jsonapi-resources.rb +27 -0
  39. metadata +223 -0
@@ -0,0 +1,262 @@
1
+ module ActionDispatch
2
+ module Routing
3
+ class Mapper
4
+ Resource.class_eval do
5
+ def unformat_route(route)
6
+ JSONAPI.configuration.route_formatter.unformat(route.to_s)
7
+ end
8
+
9
+ def nested_param
10
+ :"#{unformat_route(singular)}_#{param}"
11
+ end
12
+ end
13
+
14
+ Resources.class_eval do
15
+ def format_route(route)
16
+ JSONAPI.configuration.route_formatter.format(route.to_s)
17
+ end
18
+
19
+ def jsonapi_resource(*resources, &_block)
20
+ @resource_type = resources.first
21
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
22
+
23
+ options = resources.extract_options!.dup
24
+ options[:controller] ||= @resource_type
25
+ options.merge!(res.routing_resource_options)
26
+ options[:path] = format_route(@resource_type)
27
+
28
+ if options[:except]
29
+ options[:except] << :new unless options[:except].include?(:new) || options[:except].include?('new')
30
+ options[:except] << :edit unless options[:except].include?(:edit) || options[:except].include?('edit')
31
+ else
32
+ options[:except] = [:new, :edit]
33
+ end
34
+
35
+ if res._immutable
36
+ options[:except] << :create unless options[:except].include?(:create) || options[:except].include?('create')
37
+ options[:except] << :update unless options[:except].include?(:update) || options[:except].include?('update')
38
+ options[:except] << :destroy unless options[:except].include?(:destroy) || options[:except].include?('destroy')
39
+ end
40
+
41
+ resource @resource_type, options do
42
+ # :nocov:
43
+ if @scope.respond_to? :[]=
44
+ # Rails 4
45
+ @scope[:jsonapi_resource] = @resource_type
46
+
47
+ if block_given?
48
+ yield
49
+ else
50
+ jsonapi_relationships
51
+ end
52
+ else
53
+ # Rails 5
54
+ jsonapi_resource_scope(SingletonResource.new(@resource_type, api_only?, @scope[:shallow], options), @resource_type) do
55
+ if block_given?
56
+ yield
57
+ else
58
+ jsonapi_relationships
59
+ end
60
+ end
61
+ end
62
+ # :nocov:
63
+ end
64
+ end
65
+
66
+ def jsonapi_relationships(options = {})
67
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
68
+ res._relationships.each do |relationship_name, relationship|
69
+ if relationship.is_a?(JSONAPI::Relationship::ToMany)
70
+ jsonapi_links(relationship_name, options)
71
+ jsonapi_related_resources(relationship_name, options)
72
+ else
73
+ jsonapi_link(relationship_name, options)
74
+ jsonapi_related_resource(relationship_name, options)
75
+ end
76
+ end
77
+ end
78
+
79
+ def jsonapi_resources(*resources, &_block)
80
+ @resource_type = resources.first
81
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
82
+
83
+ options = resources.extract_options!.dup
84
+ options[:controller] ||= @resource_type
85
+ options.merge!(res.routing_resource_options)
86
+
87
+ options[:param] = :id
88
+
89
+ options[:path] = format_route(@resource_type)
90
+
91
+ if res.resource_key_type == :uuid
92
+ options[:constraints] ||= {}
93
+ options[:constraints][:id] ||= /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/
94
+ end
95
+
96
+ if options[:except]
97
+ options[:except] = Array(options[:except])
98
+ options[:except] << :new unless options[:except].include?(:new) || options[:except].include?('new')
99
+ options[:except] << :edit unless options[:except].include?(:edit) || options[:except].include?('edit')
100
+ else
101
+ options[:except] = [:new, :edit]
102
+ end
103
+
104
+ if res._immutable
105
+ options[:except] << :create unless options[:except].include?(:create) || options[:except].include?('create')
106
+ options[:except] << :update unless options[:except].include?(:update) || options[:except].include?('update')
107
+ options[:except] << :destroy unless options[:except].include?(:destroy) || options[:except].include?('destroy')
108
+ end
109
+
110
+ resources @resource_type, options do
111
+ # :nocov:
112
+ if @scope.respond_to? :[]=
113
+ # Rails 4
114
+ @scope[:jsonapi_resource] = @resource_type
115
+ if block_given?
116
+ yield
117
+ else
118
+ jsonapi_relationships
119
+ end
120
+ else
121
+ # Rails 5
122
+ jsonapi_resource_scope(Resource.new(@resource_type, api_only?, @scope[:shallow], options), @resource_type) do
123
+ if block_given?
124
+ yield
125
+ else
126
+ jsonapi_relationships
127
+ end
128
+ end
129
+ end
130
+ # :nocov:
131
+ end
132
+ end
133
+
134
+ def links_methods(options)
135
+ default_methods = [:show, :create, :destroy, :update]
136
+ if only = options[:only]
137
+ Array(only).map(&:to_sym)
138
+ elsif except = options[:except]
139
+ default_methods - Array(except)
140
+ else
141
+ default_methods
142
+ end
143
+ end
144
+
145
+ def jsonapi_link(*links)
146
+ link_type = links.first
147
+ formatted_relationship_name = format_route(link_type)
148
+ options = links.extract_options!.dup
149
+
150
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
151
+ options[:controller] ||= res._type.to_s
152
+
153
+ methods = links_methods(options)
154
+
155
+ if methods.include?(:show)
156
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
157
+ action: 'show_relationship', relationship: link_type.to_s, via: [:get]
158
+ end
159
+
160
+ if res.mutable?
161
+ if methods.include?(:update)
162
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
163
+ action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
164
+ end
165
+
166
+ if methods.include?(:destroy)
167
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
168
+ action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
169
+ end
170
+ end
171
+ end
172
+
173
+ def jsonapi_links(*links)
174
+ link_type = links.first
175
+ formatted_relationship_name = format_route(link_type)
176
+ options = links.extract_options!.dup
177
+
178
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
179
+ options[:controller] ||= res._type.to_s
180
+
181
+ methods = links_methods(options)
182
+
183
+ if methods.include?(:show)
184
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
185
+ action: 'show_relationship', relationship: link_type.to_s, via: [:get]
186
+ end
187
+
188
+ if res.mutable?
189
+ if methods.include?(:create)
190
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
191
+ action: 'create_relationship', relationship: link_type.to_s, via: [:post]
192
+ end
193
+
194
+ if methods.include?(:update)
195
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
196
+ action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
197
+ end
198
+
199
+ if methods.include?(:destroy)
200
+ match "relationships/#{formatted_relationship_name}", controller: options[:controller],
201
+ action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
202
+ end
203
+ end
204
+ end
205
+
206
+ def jsonapi_related_resource(*relationship)
207
+ source = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
208
+ options = relationship.extract_options!.dup
209
+
210
+ relationship_name = relationship.first
211
+ relationship = source._relationships[relationship_name]
212
+
213
+ formatted_relationship_name = format_route(relationship.name)
214
+
215
+ if relationship.polymorphic?
216
+ options[:controller] ||= relationship.class_name.underscore.pluralize
217
+ else
218
+ related_resource = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(relationship.class_name.underscore.pluralize))
219
+ options[:controller] ||= related_resource._type.to_s
220
+ end
221
+
222
+ match "#{formatted_relationship_name}", controller: options[:controller],
223
+ relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
224
+ action: 'get_related_resource', via: [:get]
225
+ end
226
+
227
+ def jsonapi_related_resources(*relationship)
228
+ source = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
229
+ options = relationship.extract_options!.dup
230
+
231
+ relationship_name = relationship.first
232
+ relationship = source._relationships[relationship_name]
233
+
234
+ formatted_relationship_name = format_route(relationship.name)
235
+ related_resource = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(relationship.class_name.underscore))
236
+ options[:controller] ||= related_resource._type.to_s
237
+
238
+ match "#{formatted_relationship_name}", controller: options[:controller],
239
+ relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
240
+ action: 'get_related_resources', via: [:get]
241
+ end
242
+
243
+ protected
244
+ # :nocov:
245
+ def jsonapi_resource_scope(resource, resource_type) #:nodoc:
246
+ @scope = @scope.new(scope_level_resource: resource, jsonapi_resource: resource_type)
247
+
248
+ controller(resource.resource_scope) { yield }
249
+ ensure
250
+ @scope = @scope.parent
251
+ end
252
+ # :nocov:
253
+ private
254
+
255
+ def resource_type_with_module_prefix(resource = nil)
256
+ resource_name = resource || @scope[:jsonapi_resource]
257
+ [@scope[:module], resource_name].compact.collect(&:to_s).join('/')
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,27 @@
1
+ require 'jsonapi/naive_cache'
2
+ require 'jsonapi/compiled_json'
3
+ require 'jsonapi/resource'
4
+ require 'jsonapi/cached_resource_fragment'
5
+ require 'jsonapi/response_document'
6
+ require 'jsonapi/acts_as_resource_controller'
7
+ require 'jsonapi/resource_controller'
8
+ require 'jsonapi/resource_controller_metal'
9
+ require 'jsonapi/resources/version'
10
+ require 'jsonapi/configuration'
11
+ require 'jsonapi/paginator'
12
+ require 'jsonapi/formatter'
13
+ require 'jsonapi/routing_ext'
14
+ require 'jsonapi/mime_types'
15
+ require 'jsonapi/resource_serializer'
16
+ require 'jsonapi/exceptions'
17
+ require 'jsonapi/error'
18
+ require 'jsonapi/error_codes'
19
+ require 'jsonapi/request_parser'
20
+ require 'jsonapi/operation_dispatcher'
21
+ require 'jsonapi/processor'
22
+ require 'jsonapi/relationship'
23
+ require 'jsonapi/include_directives'
24
+ require 'jsonapi/operation_result'
25
+ require 'jsonapi/operation_results'
26
+ require 'jsonapi/callbacks'
27
+ require 'jsonapi/link_builder'
metadata ADDED
@@ -0,0 +1,223 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sanger-jsonapi-resources
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dan Gebhardt
8
+ - Larry Gebhardt
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2025-06-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.5'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: minitest
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: minitest-spec-rails
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: simplecov
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: concurrent-ruby-ext
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: activerecord
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '4.1'
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '4.1'
126
+ - !ruby/object:Gem::Dependency
127
+ name: railties
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '4.1'
133
+ type: :runtime
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '4.1'
140
+ - !ruby/object:Gem::Dependency
141
+ name: concurrent-ruby
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :runtime
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ description: A resource-centric approach to implementing the controllers, routes,
155
+ and serializers needed to support the JSON API spec.
156
+ email:
157
+ - dan@cerebris.com
158
+ - larry@cerebris.com
159
+ executables: []
160
+ extensions: []
161
+ extra_rdoc_files: []
162
+ files:
163
+ - LICENSE.txt
164
+ - README.md
165
+ - lib/generators/jsonapi/USAGE
166
+ - lib/generators/jsonapi/controller_generator.rb
167
+ - lib/generators/jsonapi/resource_generator.rb
168
+ - lib/generators/jsonapi/templates/jsonapi_controller.rb
169
+ - lib/generators/jsonapi/templates/jsonapi_resource.rb
170
+ - lib/jsonapi-resources.rb
171
+ - lib/jsonapi/acts_as_resource_controller.rb
172
+ - lib/jsonapi/cached_resource_fragment.rb
173
+ - lib/jsonapi/callbacks.rb
174
+ - lib/jsonapi/compiled_json.rb
175
+ - lib/jsonapi/configuration.rb
176
+ - lib/jsonapi/error.rb
177
+ - lib/jsonapi/error_codes.rb
178
+ - lib/jsonapi/exceptions.rb
179
+ - lib/jsonapi/formatter.rb
180
+ - lib/jsonapi/include_directives.rb
181
+ - lib/jsonapi/link_builder.rb
182
+ - lib/jsonapi/mime_types.rb
183
+ - lib/jsonapi/naive_cache.rb
184
+ - lib/jsonapi/operation.rb
185
+ - lib/jsonapi/operation_dispatcher.rb
186
+ - lib/jsonapi/operation_result.rb
187
+ - lib/jsonapi/operation_results.rb
188
+ - lib/jsonapi/paginator.rb
189
+ - lib/jsonapi/processor.rb
190
+ - lib/jsonapi/relationship.rb
191
+ - lib/jsonapi/relationship_builder.rb
192
+ - lib/jsonapi/request_parser.rb
193
+ - lib/jsonapi/resource.rb
194
+ - lib/jsonapi/resource_controller.rb
195
+ - lib/jsonapi/resource_controller_metal.rb
196
+ - lib/jsonapi/resource_serializer.rb
197
+ - lib/jsonapi/resources/version.rb
198
+ - lib/jsonapi/response_document.rb
199
+ - lib/jsonapi/routing_ext.rb
200
+ homepage: https://github.com/cerebris/jsonapi-resources
201
+ licenses:
202
+ - MIT
203
+ metadata: {}
204
+ post_install_message:
205
+ rdoc_options: []
206
+ require_paths:
207
+ - lib
208
+ required_ruby_version: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: '2.1'
213
+ required_rubygems_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ requirements: []
219
+ rubygems_version: 3.5.11
220
+ signing_key:
221
+ specification_version: 4
222
+ summary: Easily support JSON API in Rails.
223
+ test_files: []