hal_api-rails 0.5.0 → 0.6.0

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
- SHA256:
3
- metadata.gz: 0d17fee58879f4f95b3f32e05bd626d6242f9c2d1e321073ce48aa6c2cfb2e37
4
- data.tar.gz: f23c5f2dcee52f79701947acdb1ee6835b7ab864aaa606f065758a82617c0750
2
+ SHA1:
3
+ metadata.gz: 4f8ad6ad0044a8438881c35775259d46cce7448d
4
+ data.tar.gz: c4dd5e6a42a4cca9d744e7050a91dc6d06e335f9
5
5
  SHA512:
6
- metadata.gz: d96ae095dfa08377102ca42a3ad02294d04a44d37df600d69beb7e69428ec5621ad8e257dcca5a668f76ab19717c753cbe5e4b5bfc66b44830bf1821b10a7a9c
7
- data.tar.gz: a7889a43949e18dbf54796de43a15ce5f3868fcbf6711db4911b4f2e2d56278f8698b8bcdfd486af425904594da2be8ce9ec7f5978158bf8d66d8add2be1c2ef
6
+ metadata.gz: ae0cf7fc44f171df5972c660d732cbd837f89216e001ef76f8b9aa97a0cc25b8581e975a90efdfdee7401cc7e9ae3ad947442239119828a374806ac023b3ce3a
7
+ data.tar.gz: 9d8eb8563e870a584b7eb69696a8d205cbb03b5b6ea68b33c64913ced078a158cfc21a37fb62a0c349b2a66c4cb026a8e3448080139f27ec88bc939ebd6e0d12
@@ -9,12 +9,16 @@ module HalApi::Controller
9
9
  require 'hal_api/controller/cache'
10
10
  require 'hal_api/controller/resources'
11
11
  require 'hal_api/controller/exceptions'
12
+ require 'hal_api/controller/sorting'
13
+ require 'hal_api/controller/filtering'
12
14
  require 'hal_api/responders/api_responder'
13
15
 
14
16
  include HalApi::Controller::Actions
15
17
  include HalApi::Controller::Cache
16
18
  include HalApi::Controller::Resources
17
19
  include HalApi::Controller::Exceptions
20
+ include HalApi::Controller::Sorting
21
+ include HalApi::Controller::Filtering
18
22
 
19
23
  included do
20
24
  include Roar::Rails::ControllerAdditions
@@ -0,0 +1,107 @@
1
+ module HalApi::Controller::Filtering
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ class_eval do
6
+ class_attribute :allowed_filter_names
7
+ class_attribute :allowed_filter_types
8
+ end
9
+ end
10
+
11
+ class FilterParams < OpenStruct
12
+ def initialize(filters = {})
13
+ @filters = filters.with_indifferent_access
14
+ end
15
+
16
+ def method_missing(m, *args, &_block)
17
+ if @filters.key?(m) && args.empty?
18
+ @filters[m]
19
+ elsif m.to_s[-1] == '?' && args.empty? && @filters.key?(m.to_s.chop)
20
+ !!@filters[m.to_s.chop]
21
+ else
22
+ msg = "Unknown filter param '#{m}'"
23
+ hint = "Valid filters are: #{@filters.keys.join(' ')}"
24
+ raise HalApi::Errors::UnknownFilterError.new(msg, hint)
25
+ end
26
+ end
27
+ end
28
+
29
+ module ClassMethods
30
+ def filter_params(*args)
31
+ self.allowed_filter_names = []
32
+ self.allowed_filter_types = {}
33
+ (args || []).map do |arg|
34
+ if arg.is_a? Hash
35
+ arg.to_a.each { |key, val| add_filter_param(key.to_s, val.to_s) }
36
+ else
37
+ add_filter_param(arg.to_s)
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def add_filter_param(name, type = nil)
45
+ unless allowed_filter_names.include? name
46
+ allowed_filter_names << name
47
+ allowed_filter_types[name] = type unless type.nil?
48
+ end
49
+ end
50
+ end
51
+
52
+ def filters
53
+ @filters ||= parse_filters_param
54
+ end
55
+
56
+ private
57
+
58
+ def parse_filters_param
59
+ filters_map = {}
60
+ filters = self.class.allowed_filter_names
61
+ force_types = self.class.allowed_filter_types
62
+
63
+ # set nils
64
+ filters.each do |name|
65
+ filters_map[name] = nil
66
+ end
67
+
68
+ # parse query param
69
+ (params[:filters] || '').split(',').each do |str|
70
+ name, value = str.split('=', 2)
71
+ next unless filters_map.key?(name)
72
+
73
+ # convert/guess type of known params
74
+ filters_map[name] =
75
+ if force_types[name] == 'date'
76
+ parse_date(value)
77
+ elsif force_types[name] == 'time'
78
+ parse_time(value)
79
+ elsif value.nil?
80
+ true
81
+ elsif value.blank?
82
+ ''
83
+ elsif [false, 'false'].include? value
84
+ false
85
+ elsif [true, 'true'].include? value
86
+ true
87
+ elsif value =~ /\A[-+]?\d+\z/
88
+ value.to_i
89
+ else
90
+ value
91
+ end
92
+ end
93
+ FilterParams.new(filters_map)
94
+ end
95
+
96
+ def parse_date(str)
97
+ Date.parse(str)
98
+ rescue ArgumentError
99
+ raise HalApi::Errors::BadFilterValueError.new "Invalid filter date: '#{str}'"
100
+ end
101
+
102
+ def parse_time(str)
103
+ Time.find_zone('UTC').parse(str) || (raise ArgumentError.new 'Nil result!')
104
+ rescue ArgumentError
105
+ raise HalApi::Errors::BadFilterValueError.new "Invalid filter time: '#{str}'"
106
+ end
107
+ end
@@ -0,0 +1,61 @@
1
+ module HalApi::Controller::Sorting
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ class_eval do
6
+ class_attribute :allowed_sort_names
7
+ class_attribute :default_sort
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def sort_params(args)
13
+ self.allowed_sort_names = args[:allowed].map(&:to_s).uniq
14
+ self.default_sort = args[:default]
15
+ if default_sort && !default_sort.is_a?(Array)
16
+ self.default_sort = Array[default_sort]
17
+ end
18
+ end
19
+ end
20
+
21
+ def sorts
22
+ @sorts ||= parse_sorts_param
23
+ end
24
+
25
+ def sorted(arel)
26
+ apply_sorts = !sorts.blank? ? sorts : default_sort
27
+ if apply_sorts.blank?
28
+ super
29
+ else
30
+ arel.order(*apply_sorts)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # support ?sorts=attribute,attribute:direction params
37
+ # e.g. ?sorts=published_at,updated_at:desc
38
+ # desc is default if a direction is not specified
39
+ def parse_sorts_param
40
+ sorts_array = []
41
+ allowed_sorts = self.class.allowed_sort_names
42
+
43
+ # parse sort param for name of the column and direction
44
+ # default is descending, because I say so, and we have a bias towards the new
45
+ (params[:sorts] || '').split(',').each do |str|
46
+ name, direction = str.split(':', 2).map { |s| s.to_s.strip }
47
+ name = name.underscore
48
+ direction = direction.blank? ? 'desc' : direction.downcase
49
+ unless allowed_sorts.include?(name)
50
+ hint = "Valid sorts are: #{allowed_sorts.join(' ')}"
51
+ raise HalApi::Errors::BadSortError.new("Invalid sort: #{name}", hint)
52
+ end
53
+ unless ['asc', 'desc'].include?(direction)
54
+ hint = "Valid directions are: asc desc"
55
+ raise HalApi::Errors::BadSortError.new("Invalid sort direction: #{direction}", hint)
56
+ end
57
+ sorts_array << { name => direction }
58
+ end
59
+ sorts_array
60
+ end
61
+ end
@@ -4,10 +4,18 @@ module HalApi::Errors
4
4
 
5
5
  class ApiError < StandardError
6
6
  attr_accessor :status
7
+ attr_accessor :hint
7
8
 
8
- def initialize(message = nil, status = 500)
9
+ def initialize(message = nil, status = nil, hint = nil)
9
10
  super(message || "API Error")
10
- self.status = status
11
+ self.status = status || 500
12
+ self.hint = hint
13
+ end
14
+ end
15
+
16
+ class Forbidden < ApiError
17
+ def initialize(message = nil, hint = nil)
18
+ super(message || 'Forbidden', 403, hint)
11
19
  end
12
20
  end
13
21
 
@@ -23,6 +31,24 @@ module HalApi::Errors
23
31
  end
24
32
  end
25
33
 
34
+ class BadSortError < ApiError
35
+ def initialize(msg, hint = nil)
36
+ super(msg, 400, hint)
37
+ end
38
+ end
39
+
40
+ class UnknownFilterError < ApiError
41
+ def initialize(msg, hint = nil)
42
+ super(msg, 400, hint)
43
+ end
44
+ end
45
+
46
+ class BadFilterValueError < ApiError
47
+ def initialize(msg, hint = nil)
48
+ super(msg, 400, hint)
49
+ end
50
+ end
51
+
26
52
  module Representer
27
53
  include Roar::JSON::HAL
28
54
 
@@ -1,5 +1,5 @@
1
1
  module HalApi
2
2
  module Rails
3
- VERSION = "0.5.0"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hal_api-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Rhoden
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-08-13 00:00:00.000000000 Z
12
+ date: 2019-08-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -216,7 +216,9 @@ files:
216
216
  - lib/hal_api/controller/actions.rb
217
217
  - lib/hal_api/controller/cache.rb
218
218
  - lib/hal_api/controller/exceptions.rb
219
+ - lib/hal_api/controller/filtering.rb
219
220
  - lib/hal_api/controller/resources.rb
221
+ - lib/hal_api/controller/sorting.rb
220
222
  - lib/hal_api/errors.rb
221
223
  - lib/hal_api/paged_collection.rb
222
224
  - lib/hal_api/paged_collection_representer.rb
@@ -253,7 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
253
255
  version: '0'
254
256
  requirements: []
255
257
  rubyforge_project:
256
- rubygems_version: 2.7.6.2
258
+ rubygems_version: 2.5.2.3
257
259
  signing_key:
258
260
  specification_version: 4
259
261
  summary: JSON HAL APIs on Rails in the style of PRX