didit-sdk 1.0.0
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 +7 -0
- data/CHANGELOG.md +25 -0
- data/LICENSE +21 -0
- data/README.md +277 -0
- data/lib/didit/authentication/base64_url.rb +34 -0
- data/lib/didit/authentication/cache.rb +201 -0
- data/lib/didit/authentication/http.rb +150 -0
- data/lib/didit/authentication/issuer.rb +115 -0
- data/lib/didit/authentication/jws.rb +231 -0
- data/lib/didit/authentication/key_set.rb +89 -0
- data/lib/didit/authentication/pkce.rb +64 -0
- data/lib/didit/authentication/types.rb +175 -0
- data/lib/didit/authentication.rb +546 -0
- data/lib/didit/client.rb +211 -0
- data/lib/didit/errors.rb +153 -0
- data/lib/didit/file_part.rb +85 -0
- data/lib/didit/internal/config.rb +94 -0
- data/lib/didit/internal/errors.rb +83 -0
- data/lib/didit/internal/log.rb +41 -0
- data/lib/didit/internal/multipart.rb +60 -0
- data/lib/didit/internal/request.rb +322 -0
- data/lib/didit/internal/transport.rb +198 -0
- data/lib/didit/internal/util.rb +76 -0
- data/lib/didit/internal.rb +15 -0
- data/lib/didit/model.rb +199 -0
- data/lib/didit/page.rb +130 -0
- data/lib/didit/raw_response.rb +57 -0
- data/lib/didit/resource.rb +15 -0
- data/lib/didit/resources/account.rb +309 -0
- data/lib/didit/resources/address_validation.rb +73 -0
- data/lib/didit/resources/age_estimation.rb +110 -0
- data/lib/didit/resources/aml.rb +166 -0
- data/lib/didit/resources/aml_monitoring.rb +30 -0
- data/lib/didit/resources/analytics.rb +87 -0
- data/lib/didit/resources/bank.rb +65 -0
- data/lib/didit/resources/billing.rb +61 -0
- data/lib/didit/resources/biometric_templates.rb +234 -0
- data/lib/didit/resources/blocklist.rb +130 -0
- data/lib/didit/resources/business_sessions.rb +29 -0
- data/lib/didit/resources/businesses.rb +471 -0
- data/lib/didit/resources/cases.rb +2116 -0
- data/lib/didit/resources/customization.rb +153 -0
- data/lib/didit/resources/database_validation.rb +327 -0
- data/lib/didit/resources/document_ai.rb +145 -0
- data/lib/didit/resources/email.rb +254 -0
- data/lib/didit/resources/face_match.rb +103 -0
- data/lib/didit/resources/face_search.rb +103 -0
- data/lib/didit/resources/fraud_checks.rb +130 -0
- data/lib/didit/resources/id_verification.rb +163 -0
- data/lib/didit/resources/id_wallets.rb +1468 -0
- data/lib/didit/resources/investigator.rb +419 -0
- data/lib/didit/resources/ip.rb +68 -0
- data/lib/didit/resources/kyb.rb +256 -0
- data/lib/didit/resources/lists.rb +332 -0
- data/lib/didit/resources/monitoring_events.rb +466 -0
- data/lib/didit/resources/networks.rb +427 -0
- data/lib/didit/resources/passive_liveness.rb +103 -0
- data/lib/didit/resources/phone.rb +271 -0
- data/lib/didit/resources/pricing.rb +40 -0
- data/lib/didit/resources/proof_of_address.rb +167 -0
- data/lib/didit/resources/questionnaires.rb +170 -0
- data/lib/didit/resources/regulatory_reports.rb +314 -0
- data/lib/didit/resources/report_templates.rb +146 -0
- data/lib/didit/resources/sessions.rb +2820 -0
- data/lib/didit/resources/transactions.rb +981 -0
- data/lib/didit/resources/travel_rule.rb +1202 -0
- data/lib/didit/resources/users.rb +521 -0
- data/lib/didit/resources/wallet_screening.rb +190 -0
- data/lib/didit/resources/webhooks.rb +396 -0
- data/lib/didit/resources/workflows.rb +214 -0
- data/lib/didit/resources.rb +263 -0
- data/lib/didit/types/account.rb +11 -0
- data/lib/didit/types/account_components.rb +105 -0
- data/lib/didit/types/address_validation.rb +8 -0
- data/lib/didit/types/age_estimation.rb +89 -0
- data/lib/didit/types/aml.rb +193 -0
- data/lib/didit/types/aml_monitoring.rb +73 -0
- data/lib/didit/types/analytics.rb +62 -0
- data/lib/didit/types/bank.rb +8 -0
- data/lib/didit/types/billing.rb +18 -0
- data/lib/didit/types/biometric_templates.rb +292 -0
- data/lib/didit/types/blocklist.rb +31 -0
- data/lib/didit/types/businesses.rb +45 -0
- data/lib/didit/types/cases.rb +368 -0
- data/lib/didit/types/components.rb +12206 -0
- data/lib/didit/types/customization.rb +8 -0
- data/lib/didit/types/database_validation.rb +177 -0
- data/lib/didit/types/document_ai.rb +135 -0
- data/lib/didit/types/email.rb +116 -0
- data/lib/didit/types/face_match.rb +93 -0
- data/lib/didit/types/face_search.rb +129 -0
- data/lib/didit/types/fraud_checks.rb +8 -0
- data/lib/didit/types/id_verification.rb +231 -0
- data/lib/didit/types/id_wallets.rb +8 -0
- data/lib/didit/types/investigator.rb +221 -0
- data/lib/didit/types/ip.rb +8 -0
- data/lib/didit/types/kyb.rb +1391 -0
- data/lib/didit/types/lists.rb +111 -0
- data/lib/didit/types/monitoring_events.rb +235 -0
- data/lib/didit/types/networks.rb +120 -0
- data/lib/didit/types/passive_liveness.rb +95 -0
- data/lib/didit/types/phone.rb +69 -0
- data/lib/didit/types/proof_of_address.rb +166 -0
- data/lib/didit/types/questionnaires.rb +29 -0
- data/lib/didit/types/regulatory_reports.rb +100 -0
- data/lib/didit/types/report_templates.rb +41 -0
- data/lib/didit/types/sessions.rb +1441 -0
- data/lib/didit/types/transactions.rb +245 -0
- data/lib/didit/types/travel_rule.rb +168 -0
- data/lib/didit/types/users.rb +180 -0
- data/lib/didit/types/wallet_screening.rb +49 -0
- data/lib/didit/types/webhooks.rb +355 -0
- data/lib/didit/types/workflows.rb +32 -0
- data/lib/didit/types.rb +1681 -0
- data/lib/didit/version.rb +5 -0
- data/lib/didit/webhooks/canonical_json.rb +187 -0
- data/lib/didit/webhooks/client_methods.rb +23 -0
- data/lib/didit/webhooks/events.rb +221 -0
- data/lib/didit/webhooks/headers.rb +83 -0
- data/lib/didit/webhooks/verifier.rb +260 -0
- data/lib/didit/webhooks.rb +99 -0
- data/lib/didit-sdk.rb +4 -0
- data/lib/didit.rb +31 -0
- data/sig/didit/authentication/base64_url.rbs +10 -0
- data/sig/didit/authentication/cache.rbs +60 -0
- data/sig/didit/authentication/http.rbs +37 -0
- data/sig/didit/authentication/issuer.rbs +17 -0
- data/sig/didit/authentication/jws.rbs +41 -0
- data/sig/didit/authentication/jwt.rbs +14 -0
- data/sig/didit/authentication/key_set.rbs +25 -0
- data/sig/didit/authentication/pkce.rbs +20 -0
- data/sig/didit/authentication/types.rbs +114 -0
- data/sig/didit/authentication.rbs +81 -0
- data/sig/didit/client.rbs +61 -0
- data/sig/didit/errors.rbs +80 -0
- data/sig/didit/file_part.rbs +19 -0
- data/sig/didit/internal.rbs +199 -0
- data/sig/didit/model.rbs +42 -0
- data/sig/didit/page.rbs +34 -0
- data/sig/didit/raw_response.rbs +20 -0
- data/sig/didit/resource.rbs +8 -0
- data/sig/didit/resources/account.rbs +23 -0
- data/sig/didit/resources/address_validation.rbs +9 -0
- data/sig/didit/resources/age_estimation.rbs +9 -0
- data/sig/didit/resources/aml.rbs +10 -0
- data/sig/didit/resources/aml_monitoring.rbs +9 -0
- data/sig/didit/resources/analytics.rbs +9 -0
- data/sig/didit/resources/bank.rbs +9 -0
- data/sig/didit/resources/billing.rbs +10 -0
- data/sig/didit/resources/biometric_templates.rbs +13 -0
- data/sig/didit/resources/blocklist.rbs +11 -0
- data/sig/didit/resources/business_sessions.rbs +9 -0
- data/sig/didit/resources/businesses.rbs +22 -0
- data/sig/didit/resources/cases.rbs +103 -0
- data/sig/didit/resources/customization.rbs +10 -0
- data/sig/didit/resources/database_validation.rbs +9 -0
- data/sig/didit/resources/document_ai.rbs +9 -0
- data/sig/didit/resources/email.rbs +11 -0
- data/sig/didit/resources/face_match.rbs +9 -0
- data/sig/didit/resources/face_search.rbs +9 -0
- data/sig/didit/resources/fraud_checks.rbs +11 -0
- data/sig/didit/resources/id_verification.rbs +9 -0
- data/sig/didit/resources/id_wallets.rbs +37 -0
- data/sig/didit/resources/investigator.rbs +23 -0
- data/sig/didit/resources/ip.rbs +9 -0
- data/sig/didit/resources/kyb.rbs +12 -0
- data/sig/didit/resources/lists.rbs +20 -0
- data/sig/didit/resources/monitoring_events.rbs +16 -0
- data/sig/didit/resources/networks.rbs +25 -0
- data/sig/didit/resources/passive_liveness.rbs +9 -0
- data/sig/didit/resources/phone.rbs +11 -0
- data/sig/didit/resources/pricing.rbs +9 -0
- data/sig/didit/resources/proof_of_address.rbs +9 -0
- data/sig/didit/resources/questionnaires.rbs +13 -0
- data/sig/didit/resources/regulatory_reports.rbs +16 -0
- data/sig/didit/resources/report_templates.rbs +13 -0
- data/sig/didit/resources/sessions.rbs +78 -0
- data/sig/didit/resources/transactions.rbs +43 -0
- data/sig/didit/resources/travel_rule.rbs +62 -0
- data/sig/didit/resources/users.rbs +21 -0
- data/sig/didit/resources/wallet_screening.rbs +11 -0
- data/sig/didit/resources/webhooks.rbs +23 -0
- data/sig/didit/resources/workflows.rbs +13 -0
- data/sig/didit/resources.rbs +50 -0
- data/sig/didit/types/account.rbs +22 -0
- data/sig/didit/types/account_components.rbs +94 -0
- data/sig/didit/types/address_validation.rbs +7 -0
- data/sig/didit/types/age_estimation.rbs +80 -0
- data/sig/didit/types/aml.rbs +174 -0
- data/sig/didit/types/aml_monitoring.rbs +67 -0
- data/sig/didit/types/analytics.rbs +57 -0
- data/sig/didit/types/bank.rbs +9 -0
- data/sig/didit/types/billing.rbs +19 -0
- data/sig/didit/types/biometric_templates.rbs +268 -0
- data/sig/didit/types/blocklist.rbs +33 -0
- data/sig/didit/types/businesses.rbs +54 -0
- data/sig/didit/types/cases.rbs +414 -0
- data/sig/didit/types/components.rbs +10920 -0
- data/sig/didit/types/customization.rbs +7 -0
- data/sig/didit/types/database_validation.rbs +152 -0
- data/sig/didit/types/document_ai.rbs +123 -0
- data/sig/didit/types/email.rbs +112 -0
- data/sig/didit/types/face_match.rbs +86 -0
- data/sig/didit/types/face_search.rbs +112 -0
- data/sig/didit/types/fraud_checks.rbs +9 -0
- data/sig/didit/types/id_verification.rbs +196 -0
- data/sig/didit/types/id_wallets.rbs +55 -0
- data/sig/didit/types/investigator.rbs +212 -0
- data/sig/didit/types/ip.rbs +7 -0
- data/sig/didit/types/kyb.rbs +1254 -0
- data/sig/didit/types/lists.rbs +106 -0
- data/sig/didit/types/monitoring_events.rbs +234 -0
- data/sig/didit/types/networks.rbs +113 -0
- data/sig/didit/types/passive_liveness.rbs +87 -0
- data/sig/didit/types/phone.rbs +65 -0
- data/sig/didit/types/proof_of_address.rbs +144 -0
- data/sig/didit/types/questionnaires.rbs +30 -0
- data/sig/didit/types/regulatory_reports.rbs +101 -0
- data/sig/didit/types/report_templates.rbs +42 -0
- data/sig/didit/types/sessions.rbs +1349 -0
- data/sig/didit/types/transactions.rbs +273 -0
- data/sig/didit/types/travel_rule.rbs +188 -0
- data/sig/didit/types/users.rbs +181 -0
- data/sig/didit/types/wallet_screening.rbs +40 -0
- data/sig/didit/types/webhooks.rbs +311 -0
- data/sig/didit/types/workflows.rbs +30 -0
- data/sig/didit/webhooks/canonical_json.rbs +25 -0
- data/sig/didit/webhooks/client_methods.rbs +11 -0
- data/sig/didit/webhooks/events.rbs +125 -0
- data/sig/didit/webhooks/headers.rbs +22 -0
- data/sig/didit/webhooks/verifier.rbs +54 -0
- data/sig/didit/webhooks.rbs +37 -0
- data/sig/didit.rbs +20 -0
- metadata +300 -0
data/lib/didit/model.rb
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
require "json"
|
|
5
|
+
require "time"
|
|
6
|
+
|
|
7
|
+
module Didit
|
|
8
|
+
# Base class of every response type.
|
|
9
|
+
#
|
|
10
|
+
# A model wraps the JSON object the API returned. Typed readers convert values
|
|
11
|
+
# on access (nested objects become models, date-times become +Time+) and never
|
|
12
|
+
# raise: a value that does not have the documented shape is returned as is.
|
|
13
|
+
# Fields the SDK does not know yet stay readable with {#[]} and {#to_h}.
|
|
14
|
+
#
|
|
15
|
+
# Field types are written as +:string+, +:integer+, +:float+, +:boolean+,
|
|
16
|
+
# +:datetime+, +:date+, +:any+, a model class (or its name under +Didit::Types+),
|
|
17
|
+
# +[:array, type]+, +[:map, type]+ or +[:union, [type, ...]]+ (the first type that fits the value).
|
|
18
|
+
class Model
|
|
19
|
+
class << self
|
|
20
|
+
# The typed fields of this class and its ancestors: reader name => [JSON name, type].
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash{Symbol => Array}]
|
|
23
|
+
def fields
|
|
24
|
+
@fields ||= begin
|
|
25
|
+
parent = superclass
|
|
26
|
+
parent.is_a?(Class) && parent < Model ? Model.fields_of(parent) : {}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @api private
|
|
31
|
+
def fields_of(klass)
|
|
32
|
+
# @type var klass: singleton(Model)
|
|
33
|
+
klass.fields.dup
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Declares a typed reader +name+ for the JSON property +wire+.
|
|
37
|
+
#
|
|
38
|
+
# @return [void]
|
|
39
|
+
def field(name, wire, type = :any)
|
|
40
|
+
fields[name] = [wire, type]
|
|
41
|
+
define_method(name) do
|
|
42
|
+
# @type self: Didit::Model
|
|
43
|
+
read_field(name)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Builds an instance from a parsed JSON value; anything but an object is returned unchanged.
|
|
48
|
+
def from_json(value)
|
|
49
|
+
value.is_a?(Hash) ? new(value) : value
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Converts a parsed JSON +value+ to +type+, leniently.
|
|
53
|
+
def coerce(value, type)
|
|
54
|
+
return value if value.nil?
|
|
55
|
+
|
|
56
|
+
case type
|
|
57
|
+
when Array then coerce_container(value, type)
|
|
58
|
+
when :float then value.is_a?(Integer) ? value.to_f : value
|
|
59
|
+
when :datetime then parse_time(value)
|
|
60
|
+
when :date then parse_date(value)
|
|
61
|
+
when Symbol then value
|
|
62
|
+
else coerce_model(value, type)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def coerce_container(value, type)
|
|
69
|
+
kind, inner = type
|
|
70
|
+
if kind == :union
|
|
71
|
+
member = inner.find { |m| fits?(value, m) }
|
|
72
|
+
member ? coerce(value, member) : value
|
|
73
|
+
elsif kind == :array && value.is_a?(Array)
|
|
74
|
+
value.map { |item| coerce(item, inner) }
|
|
75
|
+
elsif kind == :map && value.is_a?(Hash)
|
|
76
|
+
value.transform_values { |item| coerce(item, inner) }
|
|
77
|
+
else
|
|
78
|
+
value
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Whether +value+ has the JSON shape of +type+ (for unions).
|
|
83
|
+
def fits?(value, type)
|
|
84
|
+
case value
|
|
85
|
+
when Hash then type.is_a?(String) || type.is_a?(Class) || (type.is_a?(Array) && type.first == :map)
|
|
86
|
+
when Array then type.is_a?(Array) && type.first == :array
|
|
87
|
+
when String then %i[string datetime date].include?(type)
|
|
88
|
+
when Integer then %i[integer float].include?(type)
|
|
89
|
+
when Float then type == :float
|
|
90
|
+
when true, false then type == :boolean
|
|
91
|
+
else false
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def coerce_model(value, type)
|
|
96
|
+
klass = type.is_a?(String) ? Didit::Types.const_get(type, false) : type
|
|
97
|
+
value.is_a?(Hash) && klass.is_a?(Class) && klass <= Model ? klass.new(value) : value
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def parse_time(value)
|
|
101
|
+
return value unless value.is_a?(String)
|
|
102
|
+
|
|
103
|
+
Time.iso8601(value.sub(" ", "T"))
|
|
104
|
+
rescue ArgumentError
|
|
105
|
+
value
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def parse_date(value)
|
|
109
|
+
return value unless value.is_a?(String)
|
|
110
|
+
|
|
111
|
+
Date.iso8601(value)
|
|
112
|
+
rescue ArgumentError
|
|
113
|
+
value
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @param data [Hash] the JSON object, as parsed (string keys); symbol keys are accepted too
|
|
118
|
+
def initialize(data = {})
|
|
119
|
+
raise ArgumentError, "#{self.class.name} needs a Hash, got #{data.class}" unless data.is_a?(Hash)
|
|
120
|
+
|
|
121
|
+
# @type var normalized: Hash[String, untyped]
|
|
122
|
+
normalized = data.each_key.all?(String) ? (_ = data.dup) : data.transform_keys(&:to_s)
|
|
123
|
+
@data = normalized.freeze
|
|
124
|
+
@cache = {}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# The raw JSON value of any property, known to the SDK or not.
|
|
128
|
+
#
|
|
129
|
+
# @param key [String, Symbol] the property name as the API sends it
|
|
130
|
+
def [](key)
|
|
131
|
+
@data[key.to_s]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Whether the API sent the property (also when its value is +null+).
|
|
135
|
+
def key?(key)
|
|
136
|
+
@data.key?(key.to_s)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# The JSON object as a Hash with symbol keys, nested objects included.
|
|
140
|
+
#
|
|
141
|
+
# @return [Hash{Symbol => Object}]
|
|
142
|
+
def to_h
|
|
143
|
+
Model.symbolize(@data)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# @return [String] the JSON object, unchanged
|
|
147
|
+
def to_json(*args)
|
|
148
|
+
JSON.generate(@data, args.first)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Pattern matching on the typed readers: +in {status: "Approved"}+.
|
|
152
|
+
def deconstruct_keys(keys)
|
|
153
|
+
fields = self.class.fields
|
|
154
|
+
# @type var out: Hash[Symbol, untyped]
|
|
155
|
+
out = {}
|
|
156
|
+
(keys || fields.keys).each { |name| out[name] = public_send(name) if fields.key?(name) }
|
|
157
|
+
out
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def ==(other)
|
|
161
|
+
other.class == self.class && other.raw_data == @data
|
|
162
|
+
end
|
|
163
|
+
alias eql? ==
|
|
164
|
+
|
|
165
|
+
def hash
|
|
166
|
+
[self.class, @data].hash
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def inspect
|
|
170
|
+
"#<#{self.class.name} #{@data.inspect}>"
|
|
171
|
+
end
|
|
172
|
+
alias to_s inspect
|
|
173
|
+
|
|
174
|
+
# @api private
|
|
175
|
+
def self.symbolize(value)
|
|
176
|
+
case value
|
|
177
|
+
when Hash then value.to_h { |k, v| [k.to_sym, symbolize(v)] }
|
|
178
|
+
when Array then value.map { |v| symbolize(v) }
|
|
179
|
+
else value
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
protected
|
|
184
|
+
|
|
185
|
+
# @api private
|
|
186
|
+
def raw_data
|
|
187
|
+
@data
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
def read_field(name)
|
|
193
|
+
return @cache[name] if @cache.key?(name)
|
|
194
|
+
|
|
195
|
+
wire, type = self.class.fields.fetch(name)
|
|
196
|
+
@cache[name] = Model.coerce(@data[wire], type)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
data/lib/didit/page.rb
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Didit
|
|
6
|
+
# One page of a list (docs/DESIGN.md section 8): the API's +{count, next, previous, results}+.
|
|
7
|
+
#
|
|
8
|
+
# page = didit.sessions.list(limit: 50)
|
|
9
|
+
# page.each { |session| ... } # this page
|
|
10
|
+
# page.auto_paging_each { |session| ... } # every page, fetched as needed
|
|
11
|
+
#
|
|
12
|
+
# +total_count+ is the API's +count+ (Enumerable#count counts the items of this page).
|
|
13
|
+
class Page
|
|
14
|
+
include Enumerable
|
|
15
|
+
|
|
16
|
+
# @return [Array] the items of this page, typed
|
|
17
|
+
attr_reader :results
|
|
18
|
+
|
|
19
|
+
# @api private
|
|
20
|
+
def initialize(client:, prepared:, item:, data:, seen: nil)
|
|
21
|
+
@client = client
|
|
22
|
+
@prepared = prepared
|
|
23
|
+
@item = item
|
|
24
|
+
@data = data.is_a?(Hash) ? data : {}
|
|
25
|
+
list = @data["results"]
|
|
26
|
+
@results = list.is_a?(Array) ? list.map { |value| Model.coerce(value, item) } : []
|
|
27
|
+
@seen = seen || [Page.normalize(prepared.uri)]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Integer, nil] the total number of items across pages
|
|
31
|
+
def total_count
|
|
32
|
+
@data["count"]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [String, nil]
|
|
36
|
+
def next_url
|
|
37
|
+
link(@data["next"])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [String, nil]
|
|
41
|
+
def previous_url
|
|
42
|
+
link(@data["previous"])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Iterates the items of this page.
|
|
46
|
+
def each(&)
|
|
47
|
+
return enum_for(:each) unless block_given?
|
|
48
|
+
|
|
49
|
+
results.each(&)
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def next_page?
|
|
54
|
+
!next_url.nil?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Fetches the next page, or returns nil on the last one.
|
|
58
|
+
# @return [Didit::Page, nil]
|
|
59
|
+
def next_page
|
|
60
|
+
url = next_url
|
|
61
|
+
return nil if url.nil?
|
|
62
|
+
|
|
63
|
+
target = resolve(url)
|
|
64
|
+
key = Page.normalize(target)
|
|
65
|
+
if @seen.include?(key)
|
|
66
|
+
raise APIResponseValidationError.new(
|
|
67
|
+
"The API returned the pagination link #{Internal::Util.display_url(target)} twice; stopping to avoid " \
|
|
68
|
+
"a loop.", status: 200
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
@client.fetch_page(@prepared, target, @item, @seen + [key])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Iterates every item of every page, fetching pages as needed.
|
|
75
|
+
# @return [Enumerator] without a block
|
|
76
|
+
def auto_paging_each(&block)
|
|
77
|
+
return enum_for(:auto_paging_each) unless block
|
|
78
|
+
|
|
79
|
+
# @type var page: Page[untyped]?
|
|
80
|
+
page = self
|
|
81
|
+
while page
|
|
82
|
+
page.results.each(&block)
|
|
83
|
+
page = page.next_page
|
|
84
|
+
end
|
|
85
|
+
nil
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# The raw value of any property of the page.
|
|
89
|
+
def [](key)
|
|
90
|
+
@data[key.to_s]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [Hash{Symbol => Object}]
|
|
94
|
+
def to_h
|
|
95
|
+
Model.symbolize(@data)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def inspect
|
|
99
|
+
"#<Didit::Page total_count=#{total_count.inspect} results=#{results.size} next=#{next_page?}>"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @api private
|
|
103
|
+
def self.normalize(uri)
|
|
104
|
+
uri = uri.dup
|
|
105
|
+
uri.fragment = nil
|
|
106
|
+
# @type var query: Array[[String, String]]
|
|
107
|
+
query = uri.query ? URI.decode_www_form(uri.query).sort : []
|
|
108
|
+
[Internal::Util.origin(uri), uri.path, query]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def link(value)
|
|
114
|
+
value.is_a?(String) && !value.strip.empty? ? value.strip : nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def resolve(url)
|
|
118
|
+
target = URI.join(@prepared.uri.to_s, url)
|
|
119
|
+
unless %w[http https].include?(target.scheme) && Internal::Util.origin(target) == @prepared.origin
|
|
120
|
+
raise APIResponseValidationError.new(
|
|
121
|
+
"Refusing to follow a pagination link to another origin (#{Internal::Util.origin(target)}); " \
|
|
122
|
+
"the API key is only sent to #{@prepared.origin}.", status: 200
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
target
|
|
126
|
+
rescue URI::Error => e
|
|
127
|
+
raise APIResponseValidationError.new("The API returned an invalid pagination link: #{e.message}", status: 200)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Didit
|
|
4
|
+
# The HTTP response behind a result, from +didit.with_raw_response+:
|
|
5
|
+
#
|
|
6
|
+
# raw = didit.with_raw_response.sessions.create(workflow_id: "...")
|
|
7
|
+
# raw.status # => 201
|
|
8
|
+
# raw.request_id # => "..."
|
|
9
|
+
# session = raw.parse
|
|
10
|
+
class RawResponse
|
|
11
|
+
# @return [Integer]
|
|
12
|
+
attr_reader :status
|
|
13
|
+
# @return [Hash{String => String}] header names in lower case
|
|
14
|
+
attr_reader :headers
|
|
15
|
+
# @return [String, nil] the body bytes (nil when a block received them)
|
|
16
|
+
attr_reader :body
|
|
17
|
+
# @return [Integer] how many retries it took
|
|
18
|
+
attr_reader :retries_taken
|
|
19
|
+
# @return [Float] seconds the last attempt took
|
|
20
|
+
attr_reader :elapsed
|
|
21
|
+
|
|
22
|
+
# @api private
|
|
23
|
+
def initialize(status:, headers:, body:, retries_taken:, elapsed:, parser:)
|
|
24
|
+
@status = status
|
|
25
|
+
@headers = headers
|
|
26
|
+
@body = body
|
|
27
|
+
@retries_taken = retries_taken
|
|
28
|
+
@elapsed = elapsed
|
|
29
|
+
@parser = parser
|
|
30
|
+
@parsed = false
|
|
31
|
+
@value = nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Integer] alias of {#status}
|
|
35
|
+
def status_code
|
|
36
|
+
status
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [String, nil]
|
|
40
|
+
def request_id
|
|
41
|
+
Internal::Util.request_id(headers)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The typed result the method returns without +with_raw_response+.
|
|
45
|
+
def parse
|
|
46
|
+
unless @parsed
|
|
47
|
+
@value = @parser.call
|
|
48
|
+
@parsed = true
|
|
49
|
+
end
|
|
50
|
+
@value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def inspect
|
|
54
|
+
"#<Didit::RawResponse status=#{status} request_id=#{request_id.inspect}>"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Didit
|
|
4
|
+
# Base class of the generated resources (+didit.sessions+, +didit.sessions.imports+, ...).
|
|
5
|
+
class Resource
|
|
6
|
+
# @param client [Didit::Client]
|
|
7
|
+
def initialize(client)
|
|
8
|
+
@client = client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def inspect
|
|
12
|
+
"#<#{self.class.name}>"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|