jsonapi-utils 0.4.6 → 0.4.7
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 +4 -4
- data/lib/jsonapi/utils.rb +6 -0
- data/lib/jsonapi/utils/exceptions.rb +11 -7
- data/lib/jsonapi/utils/response/support.rb +4 -4
- data/lib/jsonapi/utils/support/error.rb +1 -1
- data/lib/jsonapi/utils/support/filter.rb +5 -3
- data/lib/jsonapi/utils/support/filter/custom.rb +22 -0
- data/lib/jsonapi/utils/support/filter/default.rb +66 -0
- data/lib/jsonapi/utils/support/pagination.rb +103 -33
- data/lib/jsonapi/utils/support/sort.rb +45 -27
- data/lib/jsonapi/utils/version.rb +1 -1
- metadata +33 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c64468130b16c1b4247c925d9fc25a583d6134d
|
4
|
+
data.tar.gz: 8d90c469c22ed667afb6b72dc02b2fcd31997e4b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ef5754a5dbe043c4bfeb30f40532c9a893c98ce65c15b2ca0d46196386b5eaa8e77b80a59f8e4350fdaafb867cdb7fef357a342ea1a322813a09341f5af0403
|
7
|
+
data.tar.gz: da448b2469e853c89e027960810325eaf90e66191b93769ac30cb41d8e565455b37a2a23f5e923581ab8ce74abddd8065dc9b4d85539439dd97718b465ed3ebd
|
data/lib/jsonapi/utils.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
|
1
2
|
require 'jsonapi-resources'
|
2
3
|
require 'jsonapi/utils/version'
|
3
4
|
require 'jsonapi/utils/exceptions'
|
4
5
|
require 'jsonapi/utils/request'
|
5
6
|
require 'jsonapi/utils/response'
|
7
|
+
require 'jsonapi/utils/support/filter/custom'
|
8
|
+
|
9
|
+
JSONAPI::Resource.extend JSONAPI::Utils::Support::Filter::Custom
|
6
10
|
|
7
11
|
module JSONAPI
|
8
12
|
module Utils
|
@@ -10,6 +14,8 @@ module JSONAPI
|
|
10
14
|
include Response
|
11
15
|
|
12
16
|
def self.included(base)
|
17
|
+
base.include ActsAsResourceController
|
18
|
+
|
13
19
|
if base.respond_to?(:before_action)
|
14
20
|
base.before_action :jsonapi_request_handling
|
15
21
|
end
|
@@ -23,20 +23,24 @@ module JSONAPI
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class BadRequest < ::JSONAPI::Exceptions::Error
|
26
|
-
def code
|
26
|
+
def code
|
27
|
+
'400'
|
28
|
+
end
|
27
29
|
|
28
30
|
def errors
|
29
31
|
[JSONAPI::Error.new(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
code: code,
|
33
|
+
status: :bad_request,
|
34
|
+
title: 'Bad Request',
|
35
|
+
detail: 'This request is not supported.'
|
36
|
+
)]
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
class InternalServerError < ::JSONAPI::Exceptions::Error
|
39
|
-
def code
|
41
|
+
def code
|
42
|
+
'500'
|
43
|
+
end
|
40
44
|
|
41
45
|
def errors
|
42
46
|
[JSONAPI::Error.new(
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require 'jsonapi/utils/support/
|
1
|
+
require 'jsonapi/utils/support/error'
|
2
|
+
require 'jsonapi/utils/support/filter/default'
|
2
3
|
require 'jsonapi/utils/support/pagination'
|
3
4
|
require 'jsonapi/utils/support/sort'
|
4
|
-
require 'jsonapi/utils/support/error'
|
5
5
|
|
6
6
|
module JSONAPI
|
7
7
|
module Utils
|
8
8
|
module Response
|
9
9
|
module Support
|
10
10
|
include ::JSONAPI::Utils::Support::Error
|
11
|
-
include ::JSONAPI::Utils::Support::Filter
|
11
|
+
include ::JSONAPI::Utils::Support::Filter::Default
|
12
12
|
include ::JSONAPI::Utils::Support::Pagination
|
13
13
|
include ::JSONAPI::Utils::Support::Sort
|
14
14
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def correct_media_type
|
18
|
-
|
18
|
+
unless response.body.empty?
|
19
19
|
response.headers['Content-Type'] = JSONAPI::MEDIA_TYPE
|
20
20
|
end
|
21
21
|
end
|
@@ -17,9 +17,11 @@ module JSONAPI
|
|
17
17
|
|
18
18
|
def filter_params
|
19
19
|
@_filter_params ||=
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
case params[:filter]
|
21
|
+
when Hash, ActionController::Parameters
|
22
|
+
default_filters.each_with_object({}) do |field, hash|
|
23
|
+
unformatted_field = @request.unformat_key(field)
|
24
|
+
hash[unformatted_field] = params[:filter][field]
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module JSONAPI::Utils::Support::Filter
|
2
|
+
module Custom
|
3
|
+
def _custom_filters
|
4
|
+
@_allowed_custom_filters || []
|
5
|
+
end
|
6
|
+
|
7
|
+
def custom_filters(*attrs)
|
8
|
+
attrs.each { |attr| custom_filter(attr) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def custom_filter(attr)
|
12
|
+
attr = attr.to_sym
|
13
|
+
@_allowed_filters[attr] = {}
|
14
|
+
|
15
|
+
if !@_allowed_custom_filters.is_a?(Array)
|
16
|
+
@_allowed_custom_filters = Array(attr)
|
17
|
+
elsif @_allowed_custom_filters.include?(attr)
|
18
|
+
@_allowed_custom_filters.push(attr)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module JSONAPI::Utils::Support::Filter
|
2
|
+
module Default
|
3
|
+
# Apply default equality filters.
|
4
|
+
# e.g.: User.where(name: 'Foobar')
|
5
|
+
#
|
6
|
+
# @param records [ActiveRecord::Relation, Array] collection of records
|
7
|
+
# e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
|
8
|
+
#
|
9
|
+
# @param options [Hash] JU's options
|
10
|
+
# e.g.: { filter: false, paginate: false }
|
11
|
+
#
|
12
|
+
# @return [ActiveRecord::Relation, Array]
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def apply_filter(records, options = {})
|
16
|
+
if apply_filter?(records, options)
|
17
|
+
records.where(filter_params)
|
18
|
+
else
|
19
|
+
records
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Check whether default filters should be applied.
|
24
|
+
#
|
25
|
+
# @param records [ActiveRecord::Relation, Array] collection of records
|
26
|
+
# e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
|
27
|
+
#
|
28
|
+
# @param options [Hash] JU's options
|
29
|
+
# e.g.: { filter: false, paginate: false }
|
30
|
+
#
|
31
|
+
# @return [Boolean]
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
def apply_filter?(records, options = {})
|
35
|
+
params[:filter].present? && records.respond_to?(:where) &&
|
36
|
+
(options[:filter].nil? || options[:filter])
|
37
|
+
end
|
38
|
+
|
39
|
+
# Build a Hash with the default filters.
|
40
|
+
#
|
41
|
+
# @return [Hash, NilClass]
|
42
|
+
#
|
43
|
+
# @api public
|
44
|
+
def filter_params
|
45
|
+
@_filter_params ||=
|
46
|
+
case params[:filter]
|
47
|
+
when Hash, ActionController::Parameters
|
48
|
+
default_filters.each_with_object({}) do |field, hash|
|
49
|
+
unformatted_field = @request.unformat_key(field)
|
50
|
+
hash[unformatted_field] = params[:filter][field]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Take all allowed filters and remove the custom ones.
|
58
|
+
#
|
59
|
+
# @return [Array]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
def default_filters
|
63
|
+
params[:filter].keys.map(&:to_sym) - @request.resource_klass._custom_filters
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -2,63 +2,133 @@ module JSONAPI
|
|
2
2
|
module Utils
|
3
3
|
module Support
|
4
4
|
module Pagination
|
5
|
+
# Apply proper pagination to the records.
|
6
|
+
#
|
7
|
+
# @param records [ActiveRecord::Relation, Array] collection of records
|
8
|
+
# e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
|
9
|
+
#
|
10
|
+
# @param options [Hash] JU's options
|
11
|
+
# e.g.: { resource: V2::UserResource, count: 100 }
|
12
|
+
#
|
13
|
+
# @return [ActiveRecord::Relation, Array]
|
14
|
+
#
|
15
|
+
# @api public
|
5
16
|
def apply_pagination(records, options = {})
|
6
17
|
return records unless apply_pagination?(options)
|
7
|
-
|
18
|
+
records.is_a?(Array) ? records[paginate_with(:range)] : paginate_with(:paginator).apply(records, nil)
|
19
|
+
end
|
8
20
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
21
|
+
# Mount pagination params for JSONAPI::ResourcesOperationResult.
|
22
|
+
# It can also be used anywhere else as a helper method.
|
23
|
+
#
|
24
|
+
# @param records [ActiveRecord::Relation, Array] collection of records
|
25
|
+
# e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
|
26
|
+
#
|
27
|
+
# @param options [Hash] JU's options
|
28
|
+
# e.g.: { resource: V2::UserResource, count: 100 }
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
# e.g.: {"first"=>{"number"=>1, "size"=>2}, "next"=>{"number"=>2, "size"=>2}, "last"=>{"number"=>2, "size"=>2}}
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
def pagination_params(records, options)
|
35
|
+
return {} unless JSONAPI.configuration.top_level_links_include_pagination
|
36
|
+
paginator.links_page_params(record_count: count_records(records, options))
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Define the paginator object to be used in the response's pagination.
|
42
|
+
#
|
43
|
+
# @return [PagedPaginator, OffsetPaginator]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
def paginator
|
47
|
+
@paginator ||= paginator_klass.new(page_params)
|
15
48
|
end
|
16
49
|
|
50
|
+
# Returns the paginator class to be used in the response's pagination.
|
51
|
+
#
|
52
|
+
# @return [Paginator]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
def paginator_klass
|
56
|
+
"#{JSONAPI.configuration.default_paginator}_paginator".classify.constantize
|
57
|
+
end
|
58
|
+
|
59
|
+
# Check whether pagination should be applied to the response.
|
60
|
+
#
|
61
|
+
# @return [Boolean]
|
62
|
+
#
|
63
|
+
# @api private
|
17
64
|
def apply_pagination?(options)
|
18
65
|
JSONAPI.configuration.default_paginator != :none &&
|
19
66
|
(options[:paginate].nil? || options[:paginate])
|
20
67
|
end
|
21
68
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
69
|
+
# Creates an instance of ActionController::Parameters for page params.
|
70
|
+
#
|
71
|
+
# @return [ActionController::Parameters]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def page_params
|
75
|
+
@page_params ||= begin
|
76
|
+
page = @request.params.to_unsafe_hash['page'] || {}
|
77
|
+
ActionController::Parameters.new(page)
|
31
78
|
end
|
32
79
|
end
|
33
80
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
81
|
+
# Define the paginator or range according to the pagination strategy.
|
82
|
+
#
|
83
|
+
# @param kind [Symbol] pagination object's kind
|
84
|
+
# e.g.: :paginator or :range
|
85
|
+
#
|
86
|
+
# @return [PagedPaginator, OffsetPaginator, Range]
|
87
|
+
# e.g.: #<PagedPaginator:0x00561ed06dc5a0 @number=1, @size=2>
|
88
|
+
# 0..9
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
def paginate_with(kind)
|
92
|
+
@pagination ||=
|
93
|
+
case kind
|
94
|
+
when :paginator then paginator
|
95
|
+
when :range then pagination_range
|
42
96
|
end
|
43
97
|
end
|
44
98
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
99
|
+
# Define a pagination range for objects which quack like Arrays.
|
100
|
+
#
|
101
|
+
# @return [Range]
|
102
|
+
# e.g.: 0..9
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def pagination_range
|
106
|
+
case JSONAPI.configuration.default_paginator
|
107
|
+
when :paged
|
49
108
|
number = page_params['number'].to_i.nonzero? || 1
|
50
109
|
size = page_params['size'].to_i.nonzero? || JSONAPI.configuration.default_page_size
|
51
|
-
|
52
|
-
|
53
|
-
@_paginator ||= OffsetPaginator.new(page_params)
|
110
|
+
(number - 1) * size..number * size - 1
|
111
|
+
when :offset
|
54
112
|
offset = page_params['offset'].to_i.nonzero? || 0
|
55
113
|
limit = page_params['limit'].to_i.nonzero? || JSONAPI.configuration.default_page_size
|
56
|
-
|
114
|
+
offset..offset + limit - 1
|
57
115
|
else
|
58
|
-
|
116
|
+
paginator.pagination_range(page_params)
|
59
117
|
end
|
60
118
|
end
|
61
119
|
|
120
|
+
# Count records in order to build a proper pagination and to fill up the "record_count" response's member.
|
121
|
+
#
|
122
|
+
# @param records [ActiveRecord::Relation, Array] collection of records
|
123
|
+
# e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
|
124
|
+
#
|
125
|
+
# @param options [Hash] JU's options
|
126
|
+
# e.g.: { resource: V2::UserResource, count: 100 }
|
127
|
+
#
|
128
|
+
# @return [Integer]
|
129
|
+
# e.g.: 42
|
130
|
+
#
|
131
|
+
# @api private
|
62
132
|
def count_records(records, options)
|
63
133
|
if options[:count].present?
|
64
134
|
options[:count]
|
@@ -1,35 +1,53 @@
|
|
1
|
-
module JSONAPI
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module JSONAPI::Utils::Support
|
2
|
+
module Sort
|
3
|
+
# Apply sort on result set (ascending by default).
|
4
|
+
# e.g.: User.order(:first_name)
|
5
|
+
#
|
6
|
+
# @param records [ActiveRecord::Relation, Array] collection of records
|
7
|
+
# e.g.: User.all or [{ id: 1, name: 'Tiago' }, { id: 2, name: 'Doug' }]
|
8
|
+
#
|
9
|
+
# @return [ActiveRecord::Relation, Array]
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
def apply_sort(records)
|
13
|
+
return records unless params[:sort].present?
|
7
14
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
if records.is_a?(Array)
|
16
|
+
records.sort { |a, b| comp = 0; eval(sort_criteria) }
|
17
|
+
elsif records.respond_to?(:order)
|
18
|
+
records.order(sort_params)
|
19
|
+
end
|
20
|
+
end
|
14
21
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
# Build the criteria to be evaluated wthen applying sort
|
23
|
+
# on Array of Hashes (ascending by default).
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def sort_criteria
|
29
|
+
@sort_criteria ||=
|
30
|
+
sort_params.reduce('') do |sum, (key, value)|
|
31
|
+
comparables = ["a[:#{key}]", "b[:#{key}]"]
|
32
|
+
comparables.reverse! if value == :desc
|
33
|
+
sum + "comp = comp == 0 ? #{comparables.join(' <=> ')} : comp; "
|
21
34
|
end
|
35
|
+
end
|
22
36
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
# Build a Hash with the sort criteria.
|
38
|
+
#
|
39
|
+
# @return [Hash, NilClass]
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
def sort_params
|
43
|
+
@_sort_params ||=
|
44
|
+
if params[:sort].present?
|
45
|
+
params[:sort].split(',').each_with_object({}) do |field, hash|
|
46
|
+
unformatted_field = @request.unformat_key(field)
|
47
|
+
desc, field = unformatted_field.to_s.match(/^([-_])?(\w+)$/i)[1..2]
|
48
|
+
hash[field] = desc.present? ? :desc : :asc
|
49
|
+
end
|
31
50
|
end
|
32
|
-
end
|
33
51
|
end
|
34
52
|
end
|
35
53
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Guedes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: jsonapi-resources
|
@@ -123,6 +123,34 @@ dependencies:
|
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: 0.1.4
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: pry
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.10.3
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 0.10.3
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: pry-byebug
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
126
154
|
description: A Rails way to get your API's data serialized through JSON API's specs
|
127
155
|
(http://jsosapi.org)
|
128
156
|
email:
|
@@ -146,6 +174,8 @@ files:
|
|
146
174
|
- lib/jsonapi/utils/response/support.rb
|
147
175
|
- lib/jsonapi/utils/support/error.rb
|
148
176
|
- lib/jsonapi/utils/support/filter.rb
|
177
|
+
- lib/jsonapi/utils/support/filter/custom.rb
|
178
|
+
- lib/jsonapi/utils/support/filter/default.rb
|
149
179
|
- lib/jsonapi/utils/support/pagination.rb
|
150
180
|
- lib/jsonapi/utils/support/sort.rb
|
151
181
|
- lib/jsonapi/utils/version.rb
|
@@ -169,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
199
|
version: '0'
|
170
200
|
requirements: []
|
171
201
|
rubyforge_project:
|
172
|
-
rubygems_version: 2.
|
202
|
+
rubygems_version: 2.5.1
|
173
203
|
signing_key:
|
174
204
|
specification_version: 4
|
175
205
|
summary: JSON::Utils is a simple way to get a full-featured JSON API serialization
|