jsonapi-resources 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,4 @@
1
+ require 'jsonapi/configuration'
1
2
  require 'jsonapi/resource_for'
2
3
  require 'jsonapi/association'
3
4
  require 'action_dispatch/routing/mapper'
@@ -24,9 +25,15 @@ module JSONAPI
24
25
 
25
26
  def create_has_many_link(association_type, association_key_value, context)
26
27
  association = self.class._associations[association_type]
27
- related_resource = self.class.resource_for(association.serialize_type_name).find_by_key(association_key_value, context)
28
+ related_resource = self.class.resource_for(association.type).find_by_key(association_key_value, context)
28
29
 
29
- @object.send(association.serialize_type_name) << related_resource.object
30
+ # ToDo: Add option to skip relations that already exist instead of returning an error?
31
+ relation = @object.send(association.type).where(association.primary_key => association_key_value).first
32
+ if relation.nil?
33
+ @object.send(association.type) << related_resource.object
34
+ else
35
+ raise JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value)
36
+ end
30
37
  end
31
38
 
32
39
  def replace_has_many_links(association_type, association_key_values, context)
@@ -35,6 +42,18 @@ module JSONAPI
35
42
  @object.send("#{association.key}=", association_key_values)
36
43
  end
37
44
 
45
+ def create_has_one_link(association_type, association_key_value, context)
46
+ association = self.class._associations[association_type]
47
+
48
+ # ToDo: Add option to skip relations that already exist instead of returning an error?
49
+ relation = @object.send("#{association.key}")
50
+ if relation.nil?
51
+ @object.send("#{association.key}=", association_key_value)
52
+ else
53
+ raise JSONAPI::Exceptions::HasOneRelationExists.new
54
+ end
55
+ end
56
+
38
57
  def replace_has_one_link(association_type, association_key_value, context)
39
58
  association = self.class._associations[association_type]
40
59
 
@@ -44,7 +63,7 @@ module JSONAPI
44
63
  def remove_has_many_link(association_type, key, context)
45
64
  association = self.class._associations[association_type]
46
65
 
47
- @object.send(association.serialize_type_name).delete(key)
66
+ @object.send(association.type).delete(key)
48
67
  end
49
68
 
50
69
  def remove_has_one_link(association_type, context)
@@ -95,7 +114,7 @@ module JSONAPI
95
114
 
96
115
  class << self
97
116
  def inherited(base)
98
- base._attributes = (_attributes || Set.new).dup
117
+ base._attributes = (_attributes || {}).dup
99
118
  base._associations = (_associations || {}).dup
100
119
  base._allowed_filters = (_allowed_filters || Set.new).dup
101
120
 
@@ -119,14 +138,13 @@ module JSONAPI
119
138
 
120
139
  # Methods used in defining a resource class
121
140
  def attributes(*attrs)
122
- @_attributes.merge attrs
123
141
  attrs.each do |attr|
124
142
  attribute(attr)
125
143
  end
126
144
  end
127
145
 
128
- def attribute(attr)
129
- @_attributes.add attr
146
+ def attribute(attr, options = {})
147
+ @_attributes[attr] = options
130
148
  define_method attr do
131
149
  @object.send(attr)
132
150
  end unless method_defined?(attr)
@@ -136,6 +154,10 @@ module JSONAPI
136
154
  end unless method_defined?("#{attr}=")
137
155
  end
138
156
 
157
+ def default_attribute_options
158
+ {format: :default}
159
+ end
160
+
139
161
  def has_one(*attrs)
140
162
  _associate(Association::HasOne, *attrs)
141
163
  end
@@ -161,13 +183,17 @@ module JSONAPI
161
183
  end
162
184
 
163
185
  # Override in your resource to filter the updateable keys
164
- def updateable(keys, context = nil)
165
- keys
186
+ def updateable_fields(context)
187
+ fields
166
188
  end
167
189
 
168
190
  # Override in your resource to filter the createable keys
169
- def createable(keys, context = nil)
170
- keys
191
+ def createable_fields(context)
192
+ fields
193
+ end
194
+
195
+ def fields
196
+ _updateable_associations | _attributes.keys
171
197
  end
172
198
 
173
199
  # Override this method if you have more complex requirements than this basic find method provides
@@ -178,7 +204,7 @@ module JSONAPI
178
204
  filters.each do |filter, value|
179
205
  if _associations.include?(filter)
180
206
  if _associations[filter].is_a?(JSONAPI::Association::HasMany)
181
- includes.push(filter.to_sym)
207
+ includes.push(filter)
182
208
  where_filters["#{filter}.#{_associations[filter].primary_key}"] = value
183
209
  else
184
210
  where_filters["#{_associations[filter].key}"] = value
@@ -204,53 +230,6 @@ module JSONAPI
204
230
  self.new(obj)
205
231
  end
206
232
 
207
- def verify_create_params(object_params, context = nil)
208
- verify_params(object_params, createable(_updateable_associations | _attributes.to_a), context)
209
- end
210
-
211
- def verify_update_params(object_params, context = nil)
212
- verify_params(object_params, updateable(_updateable_associations | _attributes.to_a), context)
213
- end
214
-
215
- def verify_params(object_params, allowed_params, context)
216
- # push links into top level param list with attributes in order to check for invalid params
217
- if object_params[:links]
218
- object_params[:links].each do |link, value|
219
- object_params[link] = value
220
- end
221
- object_params.delete(:links)
222
- end
223
- verify_permitted_params(object_params, allowed_params)
224
-
225
- checked_attributes = {}
226
- checked_has_one_associations = {}
227
- checked_has_many_associations = {}
228
-
229
- object_params.each do |key, value|
230
- param = key.to_sym
231
-
232
- association = _associations[param]
233
-
234
- if association.is_a?(JSONAPI::Association::HasOne)
235
- checked_has_one_associations[param.to_sym] = resource_for(association.serialize_type_name).verify_key(value, context)
236
- elsif association.is_a?(JSONAPI::Association::HasMany)
237
- keys = []
238
- value.each do |value|
239
- keys.push(resource_for(association.serialize_type_name).verify_key(value, context))
240
- end
241
- checked_has_many_associations[param.to_sym] = keys
242
- else
243
- checked_attributes[param] = value
244
- end
245
- end
246
-
247
- return {
248
- attributes: checked_attributes,
249
- has_one: checked_has_one_associations,
250
- has_many: checked_has_many_associations
251
- }
252
- end
253
-
254
233
  def verify_filters(filters, context = nil)
255
234
  verified_filters = {}
256
235
  filters.each do |filter, raw_value|
@@ -261,7 +240,7 @@ module JSONAPI
261
240
  end
262
241
 
263
242
  def is_filter_association?(filter)
264
- filter == _serialize_as || _associations.include?(filter)
243
+ filter == _type || _associations.include?(filter)
265
244
  end
266
245
 
267
246
  def verify_filter(filter, raw, context = nil)
@@ -291,6 +270,10 @@ module JSONAPI
291
270
  end
292
271
 
293
272
  # quasi private class methods
273
+ def _attribute_options(attr)
274
+ default_attribute_options.merge(@_attributes[attr])
275
+ end
276
+
294
277
  def _updateable_associations
295
278
  associations = []
296
279
 
@@ -303,11 +286,12 @@ module JSONAPI
303
286
  end
304
287
 
305
288
  def _has_association?(type)
306
- @_associations.has_key?(type)
289
+ type = type.to_s
290
+ @_associations.has_key?(type.singularize.to_sym) || @_associations.has_key?(type.pluralize.to_sym)
307
291
  end
308
292
 
309
293
  def _association(type)
310
- type = type.to_sym unless type.is_a?(Symbol)
294
+ type = type.to_sym
311
295
  @_associations[type]
312
296
  end
313
297
 
@@ -315,16 +299,12 @@ module JSONAPI
315
299
  @_model_name ||= self.name.demodulize.sub(/Resource$/, '')
316
300
  end
317
301
 
318
- def _serialize_as
319
- @_serialize_as ||= self._type
320
- end
321
-
322
302
  def _key
323
303
  @_key ||= :id
324
304
  end
325
305
 
326
306
  def _as_parent_key
327
- @_as_parent_key ||= "#{_serialize_as.to_s.singularize}_#{_key}"
307
+ @_as_parent_key ||= "#{_type.to_s.singularize}_#{_key}"
328
308
  end
329
309
 
330
310
  def _allowed_filters
@@ -351,11 +331,7 @@ module JSONAPI
351
331
  end
352
332
 
353
333
  def _allowed_filter?(filter)
354
- _allowed_filters.include?(filter.to_sym)
355
- end
356
-
357
- def _validate_field(field)
358
- _attributes.include?(field) || _associations.key?(field)
334
+ _allowed_filters.include?(filter)
359
335
  end
360
336
 
361
337
  private
@@ -374,7 +350,7 @@ module JSONAPI
374
350
  end unless method_defined?(key)
375
351
 
376
352
  define_method "_#{attr}_object" do
377
- type_name = self.class._associations[attr].serialize_type_name
353
+ type_name = self.class._associations[attr].type
378
354
  resource_class = self.class.resource_for(type_name)
379
355
  if resource_class
380
356
  associated_object = @object.send attr
@@ -389,7 +365,7 @@ module JSONAPI
389
365
  end unless method_defined?(key)
390
366
 
391
367
  define_method "_#{attr}_objects" do
392
- type_name = self.class._associations[attr].serialize_type_name
368
+ type_name = self.class._associations[attr].type
393
369
  resource_class = self.class.resource_for(type_name)
394
370
  resources = []
395
371
  if resource_class
@@ -403,15 +379,6 @@ module JSONAPI
403
379
  end
404
380
  end
405
381
  end
406
-
407
- def verify_permitted_params(params, allowed_param_set)
408
- params_not_allowed = []
409
- params.keys.each do |key|
410
- param = key.to_sym
411
- params_not_allowed.push(param) unless allowed_param_set.include?(param)
412
- end
413
- raise JSONAPI::Exceptions::ParametersNotAllowed.new(params_not_allowed) if params_not_allowed.length > 0
414
- end
415
382
  end
416
383
  end
417
- end
384
+ end
@@ -15,7 +15,10 @@ module JSONAPI
15
15
 
16
16
  before_filter {
17
17
  begin
18
- @request = JSONAPI::Request.new(context, params)
18
+ @request = JSONAPI::Request.new(params, {
19
+ context: context,
20
+ key_formatter: key_formatter
21
+ })
19
22
  render_errors(@request.errors) unless @request.errors.empty?
20
23
  rescue => e
21
24
  handle_exceptions(e)
@@ -23,11 +26,13 @@ module JSONAPI
23
26
  }
24
27
 
25
28
  def index
26
- render json: JSONAPI::ResourceSerializer.new.serialize(
29
+ render json: JSONAPI::ResourceSerializer.new.serialize_to_hash(
27
30
  resource_klass.find(resource_klass.verify_filters(@request.filters, context), context),
28
- @request.includes,
29
- @request.fields,
30
- context)
31
+ include: @request.include,
32
+ fields: @request.fields,
33
+ context: context,
34
+ attribute_formatters: attribute_formatters,
35
+ key_formatter: key_formatter)
31
36
  rescue => e
32
37
  handle_exceptions(e)
33
38
  end
@@ -35,16 +40,22 @@ module JSONAPI
35
40
  def show
36
41
  keys = parse_key_array(params[resource_klass._key])
37
42
 
38
- resources = []
39
- keys.each do |key|
40
- resources.push(resource_klass.find_by_key(key, context))
43
+ if keys.length > 1
44
+ resources = []
45
+ keys.each do |key|
46
+ resources.push(resource_klass.find_by_key(key, context))
47
+ end
48
+ else
49
+ resources = resource_klass.find_by_key(keys[0], context)
41
50
  end
42
51
 
43
- render json: JSONAPI::ResourceSerializer.new.serialize(
52
+ render json: JSONAPI::ResourceSerializer.new.serialize_to_hash(
44
53
  resources,
45
- @request.includes,
46
- @request.fields,
47
- context)
54
+ include: @request.include,
55
+ fields: @request.fields,
56
+ context: context,
57
+ attribute_formatters: attribute_formatters,
58
+ key_formatter: key_formatter)
48
59
  rescue => e
49
60
  handle_exceptions(e)
50
61
  end
@@ -70,6 +81,10 @@ module JSONAPI
70
81
  process_request_operations
71
82
  end
72
83
 
84
+ def update_association
85
+ process_request_operations
86
+ end
87
+
73
88
  def update
74
89
  process_request_operations
75
90
  end
@@ -115,6 +130,20 @@ module JSONAPI
115
130
  {}
116
131
  end
117
132
 
133
+ # Control by setting in an initializer:
134
+ # JSONAPI.configuration.json_key_format = :camelized_key
135
+ #
136
+ # Override if you want to set a per controller key format.
137
+ # Must return a class derived from KeyFormatter.
138
+ def key_formatter
139
+ JSONAPI.configuration.key_formatter
140
+ end
141
+
142
+ # override to setup custom attribute_formatters
143
+ def attribute_formatters
144
+ {}
145
+ end
146
+
118
147
  def render_errors(errors, status = :bad_request)
119
148
  render(json: {errors: errors}, status: errors.count == 1 ? errors[0].status : status)
120
149
  end
@@ -138,18 +167,17 @@ module JSONAPI
138
167
  if errors.count > 0
139
168
  render :status => errors.count == 1 ? errors[0].status : :bad_request, json: {errors: errors}
140
169
  else
141
- # if patch
142
- render :status => results[0].code, json: JSONAPI::ResourceSerializer.new.serialize(resources,
143
- @request.includes,
144
- @request.fields,
145
- context)
146
- # else
147
- # result_hash = {}
148
- # resources.each do |resource|
149
- # result_hash.merge!(JSONAPI::ResourceSerializer.new.serialize(resource, @request.includes, @request.fields, context))
150
- # end
151
- # render :status => results.count == 1 ? results[0].code : :ok, json: result_hash
152
- # end
170
+ if results.length > 0 && resources.length > 0
171
+ render :status => results[0].code,
172
+ json: JSONAPI::ResourceSerializer.new.serialize_to_hash(resources.length > 1 ? resources : resources[0],
173
+ include: @request.include,
174
+ fields: @request.fields,
175
+ context: context,
176
+ attribute_formatters: attribute_formatters,
177
+ key_formatter: key_formatter)
178
+ else
179
+ render :status => results[0].code, json: nil
180
+ end
153
181
  end
154
182
  rescue => e
155
183
  handle_exceptions(e)
@@ -166,4 +194,4 @@ module JSONAPI
166
194
  end
167
195
  end
168
196
  end
169
- end
197
+ end
@@ -7,12 +7,10 @@ module JSONAPI
7
7
  module ClassMethods
8
8
  if RUBY_VERSION >= '2.0'
9
9
  def resource_for(type)
10
- begin
11
- resource_name = JSONAPI::Resource._resource_name_from_type(type)
12
- Object.const_get resource_name if resource_name
13
- rescue NameError
14
- nil
15
- end
10
+ resource_name = JSONAPI::Resource._resource_name_from_type(type)
11
+ Object.const_get resource_name if resource_name
12
+ rescue NameError
13
+ nil
16
14
  end
17
15
  else
18
16
  def resource_for(type)
@@ -1,7 +1,7 @@
1
1
  module JSONAPI
2
2
  class ResourceSerializer
3
3
 
4
- # Serializes a single resource, or an array of resources
4
+ # Converts a single resource, or an array of resources to a hash, conforming to the JSONAPI structure
5
5
  # include:
6
6
  # Purpose: determines which objects will be side loaded with the source objects in a linked section
7
7
  # Example: ['comments','author','comments.tags','author.posts']
@@ -9,45 +9,56 @@ module JSONAPI
9
9
  # Purpose: determines which fields are serialized for a resource type. This encompasses both attributes and
10
10
  # association ids in the links section for a resource. Fields are global for a resource type.
11
11
  # Example: { people: [:id, :email, :comments], posts: [:id, :title, :author], comments: [:id, :body, :post]}
12
- def serialize(source, include = [], fields = {}, context = nil)
13
- @fields = fields
14
- @context = context
12
+ def serialize_to_hash(source, options = {})
13
+ is_resource_collection = source.respond_to?(:to_ary)
14
+ return {} if source.nil? || (is_resource_collection && source.size == 0)
15
+
16
+ @fields = options.fetch(:fields, {})
17
+ include = options.fetch(:include, [])
18
+ @context = options.fetch(:context, nil)
19
+ @key_formatter = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
20
+
15
21
  @linked_objects = {}
16
22
 
17
23
  requested_associations = parse_includes(include)
18
24
 
19
- if source.respond_to?(:to_ary)
20
- return {} if source.size == 0
21
- @primary_class_name = source[0].class._serialize_as
25
+ if is_resource_collection
26
+ @primary_class_name = source[0].class._type
22
27
  else
23
- @primary_class_name = source.class._serialize_as
28
+ @primary_class_name = source.class._type
24
29
  end
25
30
 
26
31
  process_primary(source, requested_associations)
27
32
 
28
33
  primary_class_name = @primary_class_name.to_sym
29
- primary_hash = {primary_class_name => []}
30
34
 
31
35
  linked_hash = {}
36
+ primary_objects = []
32
37
  @linked_objects.each do |class_name, objects|
33
38
  class_name = class_name.to_sym
34
39
 
35
- linked = []
40
+ linked_objects = []
36
41
  objects.each_value do |object|
37
42
  if object[:primary]
38
- primary_hash[primary_class_name].push(object[:object_hash])
43
+ primary_objects.push(object[:object_hash])
39
44
  else
40
- linked.push(object[:object_hash])
45
+ linked_objects.push(object[:object_hash])
41
46
  end
42
47
  end
43
- linked_hash[class_name] = linked unless linked.empty?
48
+ linked_hash[format_key(class_name)] = linked_objects unless linked_objects.empty?
44
49
  end
45
50
 
46
- if linked_hash.size > 0
47
- primary_hash.merge!({linked: linked_hash})
51
+ if is_resource_collection
52
+ primary_hash = {format_key(primary_class_name) => primary_objects}
53
+ else
54
+ primary_hash = {format_key(primary_class_name) => primary_objects[0]}
48
55
  end
49
56
 
50
- return primary_hash
57
+ if linked_hash.size > 0
58
+ primary_hash.merge({linked: linked_hash})
59
+ else
60
+ primary_hash
61
+ end
51
62
  end
52
63
 
53
64
  private
@@ -57,7 +68,7 @@ module JSONAPI
57
68
  def parse_includes(includes)
58
69
  requested_associations = {}
59
70
  includes.each do |include|
60
- include = include.to_s if include.is_a? Symbol
71
+ include = include.to_s.underscore
61
72
 
62
73
  pos = include.index('.')
63
74
  if pos
@@ -112,14 +123,17 @@ module JSONAPI
112
123
  end
113
124
 
114
125
  def attribute_hash(source)
115
- requested = requested_fields(source.class._serialize_as)
116
- fields = source.class._attributes.to_a
126
+ requested = requested_fields(source.class._type)
127
+ fields = source.class._attributes.keys.to_a
117
128
  unless requested.nil?
118
129
  fields = requested & fields
119
130
  end
120
131
 
121
132
  source.fetchable(fields, @context).each_with_object({}) do |name, hash|
122
- hash[name] = source.send(name)
133
+ hash[format_key(name)] = format_value(source.send(name),
134
+ source.class._attribute_options(name)[:format],
135
+ source,
136
+ @context)
123
137
  end
124
138
  end
125
139
 
@@ -127,7 +141,7 @@ module JSONAPI
127
141
  # class's fetchable method
128
142
  def links_hash(source, requested_associations)
129
143
  associations = source.class._associations
130
- requested = requested_fields(source.class._serialize_as)
144
+ requested = requested_fields(source.class._type)
131
145
  fields = associations.keys
132
146
  unless requested.nil?
133
147
  fields = requested & fields
@@ -141,7 +155,7 @@ module JSONAPI
141
155
  key = association.key
142
156
 
143
157
  if field_set.include?(name)
144
- hash[name] = source.send(key)
158
+ hash[format_key(name)] = source.send(key)
145
159
  end
146
160
 
147
161
  ia = requested_associations.is_a?(Hash) ? requested_associations[name] : nil
@@ -149,7 +163,7 @@ module JSONAPI
149
163
  include_linked_object = ia && ia[:include]
150
164
  include_linked_children = ia && ia[:include_children]
151
165
 
152
- type = association.serialize_type_name
166
+ type = association.type
153
167
 
154
168
  # If the object has been serialized once it will be in the related objects list,
155
169
  # but it's possible all children won't have been captured. So we must still go
@@ -157,13 +171,14 @@ module JSONAPI
157
171
  if include_linked_object || include_linked_children
158
172
  if association.is_a?(JSONAPI::Association::HasOne)
159
173
  object = source.send("_#{name}_object")
160
-
161
- id = object.send(association.primary_key)
162
- associations_only = already_serialized?(type, id)
163
- if include_linked_object && !associations_only
164
- add_linked_object(type, id, object_hash(object, ia[:include_related]))
165
- elsif include_linked_children || associations_only
166
- links_hash(object, ia[:include_related])
174
+ if object
175
+ id = object.send(association.primary_key)
176
+ associations_only = already_serialized?(type, id)
177
+ if include_linked_object && !associations_only
178
+ add_linked_object(type, id, object_hash(object, ia[:include_related]))
179
+ elsif include_linked_children || associations_only
180
+ links_hash(object, ia[:include_related])
181
+ end
167
182
  end
168
183
  elsif association.is_a?(JSONAPI::Association::HasMany)
169
184
  objects = source.send("_#{name}_objects")
@@ -183,16 +198,20 @@ module JSONAPI
183
198
  end
184
199
 
185
200
  def already_serialized?(type, id)
201
+ type = format_key(type)
186
202
  return @linked_objects.key?(type) && @linked_objects[type].key?(id)
187
203
  end
188
204
 
189
205
  # Sets that an object should be included in the primary document of the response.
190
206
  def set_primary(type, id)
207
+ type = format_key(type)
191
208
  @linked_objects[type][id][:primary] = true
192
209
  end
193
210
 
194
211
  # Collects the hashes for all objects processed by the serializer
195
212
  def add_linked_object(type, id, object_hash, primary = false)
213
+ type = format_key(type)
214
+
196
215
  unless @linked_objects.key?(type)
197
216
  @linked_objects[type] = {}
198
217
  end
@@ -205,5 +224,14 @@ module JSONAPI
205
224
  @linked_objects[type].store(id, {primary: primary, object_hash: object_hash})
206
225
  end
207
226
  end
227
+
228
+ def format_key(key)
229
+ @key_formatter.format(key)
230
+ end
231
+
232
+ def format_value(value, format, source, context)
233
+ value_formatter = JSONAPI::ValueFormatter.value_formatter_for(format)
234
+ value_formatter.format(value, source, context)
235
+ end
208
236
  end
209
- end
237
+ end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -47,7 +47,7 @@ module ActionDispatch
47
47
  end
48
48
 
49
49
  def links_methods(options)
50
- default_methods = [:show, :create, :destroy]
50
+ default_methods = [:show, :create, :destroy, :update]
51
51
  if only = options[:only]
52
52
  Array(only).map(&:to_sym)
53
53
  elsif except = options[:except]
@@ -73,6 +73,10 @@ module ActionDispatch
73
73
  match "links/#{link_type}", controller: res._type.to_s, action: 'create_association', association: link_type.to_s, via: [:post]
74
74
  end
75
75
 
76
+ if methods.include?(:update)
77
+ match "links/#{link_type}", controller: res._type.to_s, action: 'update_association', association: link_type.to_s, via: [:put]
78
+ end
79
+
76
80
  if methods.include?(:destroy)
77
81
  match "links/#{link_type}", controller: res._type.to_s, action: 'destroy_association', association: link_type.to_s, via: [:delete]
78
82
  end
@@ -94,6 +98,10 @@ module ActionDispatch
94
98
  match "links/#{link_type}", controller: res._type.to_s, action: 'create_association', association: link_type.to_s, via: [:post]
95
99
  end
96
100
 
101
+ if methods.include?(:update) && res._association(link_type).acts_as_set
102
+ match "links/#{link_type}", controller: res._type.to_s, action: 'update_association', association: link_type.to_s, via: [:put]
103
+ end
104
+
97
105
  if methods.include?(:destroy)
98
106
  match "links/#{link_type}/:keys", controller: res._type.to_s, action: 'destroy_association', association: link_type.to_s, via: [:delete]
99
107
  end
@@ -1,2 +1,4 @@
1
1
  require 'jsonapi/resource'
2
2
  require 'jsonapi/resources/version'
3
+ require 'jsonapi/configuration'
4
+ require 'jsonapi/formatter'