standardapi 6.0.0.15 → 6.0.0.24

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbc6b3f7345e1df82060abcc37ee0bcf5f11b88863e1cdab4299f514129b44f6
4
- data.tar.gz: cae2c3d6859933c99ac13f0704e35997e3c10603f53d325b3a8ace63607fce94
3
+ metadata.gz: b5c4c41da6b869e919e53b048048c8b3c69aae01c1ce04ec3ebddf03d7e6217a
4
+ data.tar.gz: df1ab4c4111e74959f85cc0ba5a79cd580d419d97a90adcfb08dac70335fd74c
5
5
  SHA512:
6
- metadata.gz: 75a1555b14bbbcfd99f2dcd31cbba472a157c0066a22d597cd1fff9daa7c4f53e1c6461c21c8adde888715a90df07ae7e4e8eb48467b702a7ba45e6dba21de10
7
- data.tar.gz: a9deedd375a788e22502b4caea542fdbe935ac6f4d594d8e46ceb79bcf9202e5813b795df9c60c7360ef84a9068b5388d862e95734e9bd05f427f4286ff3d114
6
+ metadata.gz: a035e59b5e886a620d9ccb95d316ca436a72c5b9ac4fb59b7cd85e4d484931d33c349a162ba0bd79bc6f09169ec8bb842902b984b356d83a9844f696dd643fde
7
+ data.tar.gz: 5e0e1df8b36ab9bfa6ef7c2043b32c36cc6df9e4b1b772e8b848034a18cadafddaaa9b561e54aad4d2c2e46512c6a1f0cd0b0b8ff8a52e2b2b4c82acc2d51bb1
@@ -5,6 +5,7 @@ module StandardAPI
5
5
  klass.helper_method :includes, :orders, :model, :resource_limit,
6
6
  :default_limit, :preloadables
7
7
  klass.before_action :set_standardapi_headers
8
+ klass.rescue_from StandardAPI::UnpermittedParameters, with: :bad_request
8
9
  klass.append_view_path(File.join(File.dirname(__FILE__), 'views'))
9
10
  klass.extend(ClassMethods)
10
11
  end
@@ -20,7 +21,8 @@ module StandardAPI
20
21
  end
21
22
 
22
23
  def index
23
- instance_variable_set("@#{model.model_name.plural}", resources.limit(limit).offset(params[:offset]).sort(orders))
24
+ records = preloadables(resources.limit(limit).offset(params[:offset]).sort(orders), includes)
25
+ instance_variable_set("@#{model.model_name.plural}", records)
24
26
  end
25
27
 
26
28
  def calculate
@@ -37,7 +39,8 @@ module StandardAPI
37
39
  end
38
40
 
39
41
  def show
40
- instance_variable_set("@#{model.model_name.singular}", resources.find(params[:id]))
42
+ record = preloadables(resources, includes).find(params[:id])
43
+ instance_variable_set("@#{model.model_name.singular}", record)
41
44
  end
42
45
 
43
46
  def new
@@ -92,6 +95,33 @@ module StandardAPI
92
95
  resources.find(params[:id]).destroy!
93
96
  head :no_content
94
97
  end
98
+
99
+ def remove_resource
100
+ resource = resources.find(params[:id])
101
+ subresource_class = resource.association(params[:relationship]).klass
102
+ subresource = subresource_class.find_by_id(params[:resource_id])
103
+
104
+ if(subresource)
105
+ result = resource.send(params[:relationship]).delete(subresource)
106
+ head result ? :no_content : :bad_request
107
+ else
108
+ head :not_found
109
+ end
110
+ end
111
+
112
+ def add_resource
113
+ resource = resources.find(params[:id])
114
+
115
+ subresource_class = resource.association(params[:relationship]).klass
116
+ subresource = subresource_class.find_by_id(params[:resource_id])
117
+ if(subresource)
118
+ result = resource.send(params[:relationship]) << subresource
119
+ head result ? :created : :bad_request
120
+ else
121
+ head :not_found
122
+ end
123
+
124
+ end
95
125
 
96
126
  # Override if you want to support masking
97
127
  def current_mask
@@ -109,6 +139,10 @@ module StandardAPI
109
139
 
110
140
  private
111
141
 
142
+ def bad_request(exception)
143
+ render body: exception.to_s, status: :bad_request
144
+ end
145
+
112
146
  def set_standardapi_headers
113
147
  headers['StandardAPI-Version'] = StandardAPI::VERSION
114
148
  end
@@ -175,13 +209,13 @@ module StandardAPI
175
209
  end
176
210
 
177
211
  def includes
178
- @includes ||= StandardAPI::Includes.normalize(params[:include])
212
+ @includes ||= StandardAPI::Includes.sanitize(params[:include], model_includes)
179
213
  end
180
214
 
181
- def preloadables(record, iclds)
215
+ def preloadables(record, includes)
182
216
  preloads = {}
183
217
 
184
- iclds.each do |key, value|
218
+ includes.each do |key, value|
185
219
  if reflection = record.klass.reflections[key]
186
220
  case value
187
221
  when true
@@ -307,7 +341,9 @@ module StandardAPI
307
341
 
308
342
  column = column == '*' ? Arel.star : column.to_sym
309
343
  if functions.include?(func.to_s.downcase)
310
- @selects << ((defined?(@model) ? @model : model).arel_table[column].send(func))
344
+ node = (defined?(@model) ? @model : model).arel_table[column].send(func)
345
+ node.distinct = true if params[:distinct]
346
+ @selects << node
311
347
  end
312
348
  end
313
349
  end
@@ -0,0 +1,13 @@
1
+ module StandardAPI
2
+ class StandardAPIError < StandardError
3
+ end
4
+
5
+ class UnpermittedParameters < StandardAPIError
6
+ attr_reader :params
7
+
8
+ def initialize(params)
9
+ @params = params
10
+ super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.map { |e| e.inspect }.join(", ")}")
11
+ end
12
+ end
13
+ end
@@ -58,7 +58,7 @@ module StandardAPI
58
58
  end
59
59
 
60
60
  def cached_at_columns_for_includes(includes)
61
- includes.select { |k,v| !['when', 'where', 'limit', 'order', 'distinct'].include?(k) }.map do |k, v|
61
+ includes.select { |k,v| !['when', 'where', 'limit', 'order', 'distinct', 'distinct_on'].include?(k) }.map do |k, v|
62
62
  ["#{k}_cached_at"] + cached_at_columns_for_includes(v).map { |v2| "#{k}_#{v2}" }
63
63
  end.flatten
64
64
  end
@@ -103,8 +103,6 @@ module StandardAPI
103
103
 
104
104
  def json_column_type(sql_type)
105
105
  case sql_type
106
- when /character varying(\(\d+\))?/
107
- 'string'
108
106
  when 'timestamp without time zone'
109
107
  'datetime'
110
108
  when 'time without time zone'
@@ -133,10 +131,12 @@ module StandardAPI
133
131
  'string'
134
132
  when 'boolean'
135
133
  'boolean'
136
- when 'geometry'
137
- 'ewkb'
138
134
  when 'uuid' # TODO: should be uuid
139
135
  'string'
136
+ when /character varying(\(\d+\))?/
137
+ 'string'
138
+ when /^geometry/
139
+ 'ewkb'
140
140
  end
141
141
  end
142
142
 
@@ -17,17 +17,29 @@ module StandardAPI
17
17
  includes.flatten.compact.each { |v| normalized.merge!(normalize(v)) }
18
18
  when Hash, ActionController::Parameters
19
19
  includes.each_pair do |k, v|
20
- if ['limit', 'when', 'where', 'order'].include?(k.to_s) # Where and order are not normalized (sanitation happens in activerecord-filter)
21
- normalized[k] = case v
20
+ normalized[k] = case k.to_s
21
+ when 'when', 'where', 'order'
22
+ case v
22
23
  when Hash then v.to_h
23
24
  when ActionController::Parameters then v.to_unsafe_h
24
25
  end
25
- elsif k.to_s == 'distinct'
26
- normalized[k] = case v
26
+ when 'limit'
27
+ case v
28
+ when String then v.to_i
29
+ when Integer then v
30
+ end
31
+ when 'distinct'
32
+ case v
33
+ when 'true' then true
34
+ when 'false' then false
35
+ end
36
+ when 'distinct_on'
37
+ case v
27
38
  when String then v
39
+ when Array then v
28
40
  end
29
41
  else
30
- normalized[k] = normalize(v)
42
+ normalize(v)
31
43
  end
32
44
  end
33
45
  when nil
@@ -58,14 +70,12 @@ module StandardAPI
58
70
 
59
71
  permit = normalize(permit.with_indifferent_access)
60
72
  includes.each do |k, v|
61
- if permit.has_key?(k) || ['limit', 'when', 'where', 'order', 'distinct'].include?(k.to_s)
62
- permitted[k] = sanitize(v, permit[k] || {}, true)
73
+ permitted[k] = if permit.has_key?(k)
74
+ sanitize(v, permit[k] || {}, true)
75
+ elsif ['limit', 'when', 'where', 'order', 'distinct', 'distinct_on'].include?(k.to_s)
76
+ v
63
77
  else
64
- if [:raise, nil].include?(Rails.configuration.try(:action_on_unpermitted_includes))
65
- raise ActionController::UnpermittedParameters.new([k])
66
- else
67
- Rails.logger.try(:warn, "Invalid Include: #{k}")
68
- end
78
+ raise StandardAPI::UnpermittedParameters.new([k])
69
79
  end
70
80
  end
71
81
 
@@ -15,11 +15,11 @@ module StandardAPI
15
15
  key2, key3 = *key.to_s.split('.')
16
16
  permitted << sanitize({key2.to_sym => { key3.to_sym => value } }, permit)
17
17
  elsif permit.include?(key.to_s)
18
- case value
18
+ value = case value
19
19
  when Hash
20
20
  value
21
21
  when ActionController::Parameters
22
- value.to_unsafe_hash
22
+ value.permit([:asc, :desc]).to_h
23
23
  else
24
24
  value
25
25
  end
@@ -29,7 +29,7 @@ module StandardAPI
29
29
  sanitized_value = sanitize(value, subpermit)
30
30
  permitted << { key.to_sym => sanitized_value }
31
31
  else
32
- raise(ActionController::UnpermittedParameters.new([orders]))
32
+ raise(StandardAPI::UnpermittedParameters.new([orders]))
33
33
  end
34
34
  end
35
35
  when Array
@@ -48,7 +48,7 @@ module StandardAPI
48
48
  elsif permit.include?(orders.to_s)
49
49
  permitted = orders
50
50
  else
51
- raise(ActionController::UnpermittedParameters.new([orders]))
51
+ raise(StandardAPI::UnpermittedParameters.new([orders]))
52
52
  end
53
53
  end
54
54
 
@@ -57,8 +57,6 @@ module StandardAPI
57
57
  else
58
58
  permitted
59
59
  end
60
-
61
- # permitted
62
60
  end
63
61
 
64
62
  end
@@ -9,4 +9,4 @@ module StandardAPI
9
9
  end
10
10
 
11
11
  end
12
- end
12
+ end
@@ -24,6 +24,8 @@ module StandardAPI
24
24
  resources(*resources, options) do
25
25
  get :schema, on: :collection
26
26
  get :calculate, on: :collection
27
+ delete ':relationship/:resource_id' => :remove_resource, on: :member
28
+ post ':relationship/:resource_id' => :add_resource, on: :member
27
29
  block.call if block
28
30
  end
29
31
  end
@@ -51,6 +53,8 @@ module StandardAPI
51
53
  resource(*resource, options) do
52
54
  get :schema, on: :collection
53
55
  get :calculate, on: :collection
56
+ delete ':relationship/:resource_id' => :remove_resource, on: :member
57
+ post ':relationship/:resource_id' => :add_resource, on: :member
54
58
  block.call if block
55
59
  end
56
60
  end
@@ -24,7 +24,9 @@ module StandardAPI
24
24
  get resource_path(:calculate, select: selects, format: :json)
25
25
  assert_response :ok
26
26
  calculations = @controller.instance_variable_get('@calculations')
27
- assert_equal [selects.map { |s| model.send(s.keys.first, column.name) }],
27
+ expectations = selects.map { |s| model.send(s.keys.first, column.name) }
28
+ expectations = [expectations] if expectations.length > 1
29
+ assert_equal expectations,
28
30
  calculations
29
31
  end
30
32
 
@@ -1,3 +1,3 @@
1
1
  module StandardAPI
2
- VERSION = '6.0.0.15'
2
+ VERSION = '6.0.0.24'
3
3
  end
@@ -5,7 +5,7 @@ record.attributes.each do |name, value|
5
5
  end
6
6
 
7
7
  includes.each do |inc, subinc|
8
- next if ["limit", "offset", "order", "when", "where"].include?(inc)
8
+ next if ["limit", "offset", "order", "when", "where", "distinct", "distinct_on"].include?(inc)
9
9
 
10
10
  case association = record.class.reflect_on_association(inc)
11
11
  when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::ThroughReflection
@@ -14,15 +14,16 @@ includes.each do |inc, subinc|
14
14
  partial = model_partial(association.klass)
15
15
  json.set! inc do
16
16
  # TODO limit causes preloaded assocations to reload
17
- if subinc.keys.any? { |x| ["limit", "offset", "order", "when", "where"].include?(x) }
18
- if subinc['distinct']
19
- json.array! record.send(inc).filter(subinc['where']).limit(subinc['limit']).sort(subinc['order']).distinct_on(subinc['distinct']), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
20
- else
21
- json.array! record.send(inc).filter(subinc['where']).limit(subinc['limit']).sort(subinc['order']).distinct, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
22
- end
23
- else
24
- json.array! record.send(inc), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
25
- end
17
+ sub_records = record.send(inc)
18
+
19
+ sub_records = sub_records.limit(subinc['limit']) if subinc['limit']
20
+ sub_records = sub_records.offset(subinc['offset']) if subinc['offset']
21
+ sub_records = sub_records.order(subinc['order']) if subinc['order']
22
+ sub_records = sub_records.filter(subinc['where']) if subinc['where']
23
+ sub_records = sub_records.distinct if subinc['distinct']
24
+ sub_records = sub_records.distinct_on(subinc['distinct_on']) if subinc['distinct_on']
25
+
26
+ json.array! sub_records, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
26
27
  end
27
28
  end
28
29
  when ActiveRecord::Reflection::BelongsToReflection, ActiveRecord::Reflection::HasOneReflection
@@ -7,7 +7,7 @@ json.object! do
7
7
  end
8
8
 
9
9
  includes.each do |inc, subinc|
10
- next if ["limit", "offset", "order", "when", "where"].include?(inc)
10
+ next if ["limit", "offset", "order", "when", "where", "distinct", "distinct_on"].include?(inc)
11
11
 
12
12
  case association = record.class.reflect_on_association(inc)
13
13
  when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::ThroughReflection
@@ -16,15 +16,16 @@ json.object! do
16
16
  partial = model_partial(association.klass)
17
17
  json.set! inc do
18
18
  # TODO limit causes preloaded assocations to reload
19
- if subinc.keys.any? { |x| ["limit", "offset", "order", "when", "where"].include?(x) }
20
- if subinc['distinct']
21
- json.array! record.send(inc).filter(subinc['where']).limit(subinc['limit']).sort(subinc['order']).distinct_on(subinc['distinct']), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
22
- else
23
- json.array! record.send(inc).filter(subinc['where']).limit(subinc['limit']).sort(subinc['order']).distinct, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
24
- end
25
- else
26
- json.array! record.send(inc), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
27
- end
19
+ sub_records = record.send(inc)
20
+
21
+ sub_records = sub_records.limit(subinc['limit']) if subinc['limit']
22
+ sub_records = sub_records.offset(subinc['offset']) if subinc['offset']
23
+ sub_records = sub_records.order(subinc['order']) if subinc['order']
24
+ sub_records = sub_records.filter(subinc['where']) if subinc['where']
25
+ sub_records = sub_records.distinct if subinc['distinct']
26
+ sub_records = sub_records.distinct_on(subinc['distinct_on']) if subinc['distinct_on']
27
+
28
+ json.array! sub_records, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
28
29
  end
29
30
  end
30
31
  when ActiveRecord::Reflection::BelongsToReflection, ActiveRecord::Reflection::HasOneReflection
@@ -1,19 +1,16 @@
1
- if !includes.empty?
2
- instance_variable_set("@#{model.model_name.plural}", preloadables(instance_variable_get("@#{model.model_name.plural}"), includes))
1
+ if !defined?(records)
2
+ records = instance_variable_get("@#{model.model_name.plural}")
3
3
  end
4
4
 
5
- if !includes.empty? && can_cache?(model, includes)
6
- partial = model_partial(model)
7
- record_name = partial.split('/').last.to_sym
5
+ partial = model_partial(model)
6
+ partial_record_name = partial.split('/').last.to_sym
8
7
 
9
- json.cache_collection! instance_variable_get("@#{model.model_name.plural}"), key: proc { |record| cache_key(record, includes) } do |record|
10
- locals = { record: record, record_name => record, :includes => includes }
11
- json.partial! partial, locals
8
+ if !includes.empty? && can_cache?(model, includes)
9
+ json.cache_collection! records, key: proc { |record| cache_key(record, includes) } do |record|
10
+ json.partial!(partial, includes: includes, partial_record_name => record)
12
11
  end
13
12
  else
14
- partial = model_partial(model)
15
- record_name = partial.split('/').last.to_sym
16
- json.array!(instance_variable_get("@#{model.model_name.plural}")) do |record|
13
+ json.array!(records) do |record|
17
14
  sub_includes = includes.select do |key, value|
18
15
  case value
19
16
  when Hash, ActionController::Parameters
@@ -27,10 +24,6 @@ else
27
24
  end
28
25
  end
29
26
 
30
- json.partial! partial, {
31
- record: record,
32
- record_name => record,
33
- includes: sub_includes
34
- }
27
+ json.partial!(partial, includes: sub_includes, partial_record_name => record)
35
28
  end
36
29
  end
@@ -1,20 +1,17 @@
1
- if !includes.empty?
2
- instance_variable_set("@#{model.model_name.plural}", preloadables(instance_variable_get("@#{model.model_name.plural}"), includes))
1
+ if !defined?(records)
2
+ records = instance_variable_get("@#{model.model_name.plural}")
3
3
  end
4
4
 
5
+ partial = model_partial(model)
6
+ partial_record_name = partial.split('/').last.to_sym
7
+
5
8
  if !includes.empty? && can_cache?(model, includes)
6
- partial = model_partial(model)
7
- record_name = partial.split('/').last.to_sym
8
-
9
- json.cache_collection! instance_variable_get("@#{model.model_name.plural}"), key: proc {|record| cache_key(record, includes) } do |record|
10
- locals = { record: record, record_name => record, :includes => includes }
11
- json.partial! partial, locals
9
+ json.cache_collection! records, key: proc { |record| cache_key(record, includes) } do |record|
10
+ json.partial!(partial, includes: includes, partial_record_name => record)
12
11
  end
13
12
  else
14
- partial = model_partial(model)
15
- record_name = partial.split('/').last.to_sym
16
13
  json.array! do
17
- instance_variable_get("@#{model.model_name.plural}").each do |record|
14
+ records.each do |record|
18
15
  sub_includes = includes.select do |key, value|
19
16
  case value
20
17
  when Hash, ActionController::Parameters
@@ -28,11 +25,7 @@ else
28
25
  end
29
26
  end
30
27
 
31
- json.partial! partial, {
32
- record: record,
33
- record_name => record,
34
- includes: sub_includes
35
- }
28
+ json.partial!(partial, includes: sub_includes, partial_record_name => record)
36
29
  end
37
30
  end
38
31
  end
@@ -1 +1,8 @@
1
- json.partial! model_partial(model), model_partial(model).split('/').last.to_sym => instance_variable_get("@#{model.model_name.singular}"), includes: includes
1
+ if !defined?(record)
2
+ record = instance_variable_get("@#{model.model_name.singular}")
3
+ end
4
+
5
+ partial = model_partial(model)
6
+ partial_record_name = partial.split('/').last.to_sym
7
+
8
+ json.partial!(partial, partial_record_name => record, includes: includes)
@@ -1 +1,8 @@
1
- json.partial! model_partial(model), model_partial(model).split('/').last.to_sym => instance_variable_get("@#{model.model_name.singular}"), includes: includes
1
+ if !defined?(record)
2
+ record = instance_variable_get("@#{model.model_name.singular}")
3
+ end
4
+
5
+ partial = model_partial(model)
6
+ partial_record_name = partial.split('/').last.to_sym
7
+
8
+ json.partial!(partial, partial_record_name => record, includes: includes)
data/lib/standard_api.rb CHANGED
@@ -8,6 +8,7 @@ require 'active_record/sort'
8
8
  require 'active_support/core_ext/hash/indifferent_access'
9
9
 
10
10
  require 'standard_api/version'
11
+ require 'standard_api/errors'
11
12
  require 'standard_api/orders'
12
13
  require 'standard_api/includes'
13
14
  require 'standard_api/controller'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standardapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.15
4
+ version: 6.0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Bracy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-22 00:00:00.000000000 Z
11
+ date: 2019-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: minitest-reporters
154
+ name: simplecov
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
@@ -165,7 +165,7 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: simplecov
168
+ name: factory_bot_rails
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - ">="
@@ -179,7 +179,7 @@ dependencies:
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
- name: factory_bot_rails
182
+ name: faker
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
@@ -193,7 +193,7 @@ dependencies:
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  - !ruby/object:Gem::Dependency
196
- name: faker
196
+ name: byebug
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - ">="
@@ -207,7 +207,7 @@ dependencies:
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
209
  - !ruby/object:Gem::Dependency
210
- name: byebug
210
+ name: mocha
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
213
  - - ">="
@@ -221,7 +221,7 @@ dependencies:
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0'
223
223
  - !ruby/object:Gem::Dependency
224
- name: mocha
224
+ name: benchmark-ips
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
227
  - - ">="
@@ -246,6 +246,7 @@ files:
246
246
  - README.md
247
247
  - lib/standard_api.rb
248
248
  - lib/standard_api/controller.rb
249
+ - lib/standard_api/errors.rb
249
250
  - lib/standard_api/helpers.rb
250
251
  - lib/standard_api/includes.rb
251
252
  - lib/standard_api/middleware/query_encoding.rb