|
3 | 3 | module Blnk |
4 | 4 | # Resoureable module that bring some tweaks for basic REST api integration |
5 | 5 | class Resourceable < OpenStruct |
| 6 | + extend Client |
| 7 | + |
6 | 8 | class SearchResult < OpenStruct; end |
7 | 9 |
|
8 | | - include Client |
| 10 | + class DefaultSearchContract < Dry::Validation::Contract |
| 11 | + schema do |
| 12 | + required(:q).value(:string) |
| 13 | + end |
| 14 | + end |
9 | 15 |
|
10 | 16 | class << self |
11 | | - def resource_name = raise NotImplementedError |
12 | | - def id_field = :id |
| 17 | + include Dry::Monads[:result] |
| 18 | + |
| 19 | + attr_accessor :resource_name, :id_field, :create_contract, :search_contract |
13 | 20 |
|
14 | 21 | def find(id) |
15 | | - response = new.get_request(path: "/#{resource_name}/#{id}") |
16 | | - return response unless response.status.success? |
| 22 | + check_vars |
| 23 | + res = get_request(path: "/#{resource_name}/#{id}") |
| 24 | + return Success(new(res.parse)) if res.status.success? |
17 | 25 |
|
18 | | - new response.parse |
| 26 | + Failure(res.parse) |
19 | 27 | end |
20 | 28 |
|
21 | 29 | def all |
22 | | - response = new.get_request(path: "/#{resource_name}") |
23 | | - return response unless response.status.success? |
| 30 | + check_vars |
| 31 | + res = get_request(path: "/#{resource_name}") |
| 32 | + return Failure(res.parse&.symbolize_keys) unless res.status.success? |
24 | 33 |
|
25 | | - response.parse.map do |r| |
26 | | - new r |
27 | | - end |
| 34 | + Success(res.parse.map { |r| new(r) }) |
28 | 35 | end |
29 | 36 |
|
30 | 37 | def create(**args) |
31 | | - response = new.post_request( |
32 | | - path: "/#{resource_name}", |
33 | | - body: args |
34 | | - ) |
35 | | - return response unless response.status.success? |
| 38 | + contract = wrap_call(create_contract_new, args) |
| 39 | + return contract if contract.failure? |
36 | 40 |
|
37 | | - new(response.parse) |
| 41 | + res = post_request(path: "/#{resource_name}", body: contract.to_h) |
| 42 | + return Failure(res.parse&.symbolize_keys) unless res.status.success? |
| 43 | + |
| 44 | + Success(new(res.parse)) |
38 | 45 | end |
39 | 46 |
|
40 | 47 | def search(**args) |
41 | | - response = new.post_request( |
42 | | - path: "/search/#{resource_name}", |
43 | | - body: args |
44 | | - ) |
45 | | - return response unless response.status.success? |
| 48 | + contract = wrap_call(search_contract_new, args) |
| 49 | + return contract if contract.failure? |
| 50 | + |
| 51 | + res = post_request(path: "/search/#{resource_name}", body: contract.to_h) |
| 52 | + return Failure(res.parse&.symbolize_keys) unless res.status.success? |
| 53 | + |
| 54 | + result = SearchResult.new(res.parse.merge(resource_name:)) |
| 55 | + Success(result) |
| 56 | + end |
46 | 57 |
|
47 | | - sr = SearchResult.new(response.parse) |
48 | | - sr.resource_name = resource_name |
49 | | - sr |
| 58 | + def check_vars |
| 59 | + raise NotImplementedError, 'missing self.resource_name' unless resource_name |
| 60 | + raise NotImplementedError, 'missing self.id_field' unless id_field |
| 61 | + raise NotImplementedError, 'missing self.create_contract' unless create_contract |
50 | 62 | end |
| 63 | + |
| 64 | + def wrap_call(contract, args) |
| 65 | + check_vars |
| 66 | + ccall = contract.call(args) |
| 67 | + return Failure(ccall.errors.to_h) if ccall.failure? |
| 68 | + |
| 69 | + ccall |
| 70 | + end |
| 71 | + |
| 72 | + def create_contract_new |
| 73 | + return create_contract.new if create_contract |
| 74 | + |
| 75 | + raise NotImplementedError, 'missing self.create_contract' |
| 76 | + end |
| 77 | + |
| 78 | + def search_contract_new = (search_contract || DefaultSearchContract).new |
51 | 79 | end |
52 | 80 |
|
53 | | - def persisted? = table[self.class.id_field] |
54 | | - def body_data = raise NotImplementedError |
| 81 | + # table[self.class.id_field] |
| 82 | + def persisted? = public_send(self.class.id_field) |
55 | 83 | end |
56 | 84 | end |
0 commit comments