fintoc 0.1.0 → 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 +4 -4
- data/.github/pull_request_template.md +47 -0
- data/.github/workflows/ci.yml +46 -0
- data/.rubocop.yml +14 -7
- data/CHANGELOG.md +40 -0
- data/Gemfile +20 -1
- data/Gemfile.lock +237 -61
- data/README.md +286 -42
- data/Rakefile +3 -3
- data/fintoc.gemspec +3 -7
- data/lib/config/initializers/money.rb +5 -0
- data/lib/fintoc/base_client.rb +150 -0
- data/lib/fintoc/client.rb +14 -123
- data/lib/fintoc/constants.rb +4 -3
- data/lib/fintoc/errors.rb +139 -15
- data/lib/fintoc/jws.rb +83 -0
- data/lib/fintoc/utils.rb +2 -2
- data/lib/fintoc/v1/client/client.rb +12 -0
- data/lib/fintoc/v1/managers/links_manager.rb +46 -0
- data/lib/fintoc/v1/resources/account.rb +95 -0
- data/lib/fintoc/v1/resources/balance.rb +27 -0
- data/lib/fintoc/v1/resources/institution.rb +21 -0
- data/lib/fintoc/v1/resources/link.rb +85 -0
- data/lib/fintoc/v1/resources/movement.rb +62 -0
- data/lib/fintoc/v1/resources/transfer_account.rb +24 -0
- data/lib/fintoc/v2/client/client.rb +37 -0
- data/lib/fintoc/v2/managers/account_numbers_manager.rb +59 -0
- data/lib/fintoc/v2/managers/account_verifications_manager.rb +45 -0
- data/lib/fintoc/v2/managers/accounts_manager.rb +54 -0
- data/lib/fintoc/v2/managers/entities_manager.rb +36 -0
- data/lib/fintoc/v2/managers/simulate_manager.rb +30 -0
- data/lib/fintoc/v2/managers/transfers_manager.rb +56 -0
- data/lib/fintoc/v2/resources/account.rb +105 -0
- data/lib/fintoc/v2/resources/account_number.rb +105 -0
- data/lib/fintoc/v2/resources/account_verification.rb +73 -0
- data/lib/fintoc/v2/resources/entity.rb +51 -0
- data/lib/fintoc/v2/resources/transfer.rb +131 -0
- data/lib/fintoc/version.rb +1 -1
- data/lib/fintoc/webhook_signature.rb +73 -0
- data/lib/fintoc.rb +3 -0
- data/lib/tasks/simplecov_config.rb +19 -0
- metadata +35 -83
- data/lib/fintoc/resources/account.rb +0 -84
- data/lib/fintoc/resources/balance.rb +0 -24
- data/lib/fintoc/resources/institution.rb +0 -18
- data/lib/fintoc/resources/link.rb +0 -83
- data/lib/fintoc/resources/movement.rb +0 -55
- data/lib/fintoc/resources/transfer_account.rb +0 -22
data/README.md
CHANGED
@@ -13,18 +13,30 @@ Do yourself a favor: go grab some ice cubes by installing this refreshing librar
|
|
13
13
|
## Table of contents
|
14
14
|
|
15
15
|
- [Fintoc meets Ruby](#fintoc-meets-ruby)
|
16
|
+
- [Why?](#why)
|
16
17
|
- [Table of contents](#table-of-contents)
|
17
|
-
- [How to
|
18
|
+
- [How to Install](#how-to-install)
|
18
19
|
- [Quickstart](#quickstart)
|
20
|
+
- [Client Architecture](#client-architecture)
|
21
|
+
- [**API V1 Client**](#api-v1-client)
|
22
|
+
- [**API V2 Client**](#api-v2-client)
|
23
|
+
- [**Backward compatibility**](#backward-compatibility)
|
19
24
|
- [Documentation](#documentation)
|
20
25
|
- [Examples](#examples)
|
21
|
-
- [
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
- [Movements API Examples](#movements-api-examples)
|
27
|
+
- [Get accounts](#get-accounts)
|
28
|
+
- [Get movements](#get-movements)
|
29
|
+
- [Transfers API Examples](#transfers-api-examples)
|
30
|
+
- [Entities](#entities)
|
31
|
+
- [Transfer Accounts](#transfer-accounts)
|
32
|
+
- [Account Numbers](#account-numbers)
|
33
|
+
- [Transfers](#transfers)
|
34
|
+
- [Simulate](#simulate)
|
35
|
+
- [Account Verifications](#account-verifications)
|
36
|
+
- [Development](#development)
|
37
|
+
- [Dependencies](#dependencies)
|
38
|
+
- [Setup](#setup)
|
39
|
+
- [Contributing](#contributing)
|
28
40
|
|
29
41
|
## How to Install
|
30
42
|
|
@@ -36,11 +48,11 @@ gem 'fintoc'
|
|
36
48
|
|
37
49
|
And then execute:
|
38
50
|
|
39
|
-
|
51
|
+
$ bundle install
|
40
52
|
|
41
53
|
Or install it yourself as:
|
42
54
|
|
43
|
-
|
55
|
+
$ gem install fintoc
|
44
56
|
|
45
57
|
## Quickstart
|
46
58
|
|
@@ -51,37 +63,121 @@ Or install it yourself as:
|
|
51
63
|
```ruby
|
52
64
|
require 'fintoc'
|
53
65
|
|
54
|
-
client = Fintoc::Client.new('
|
55
|
-
link = client.
|
66
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
67
|
+
link = client.v1.links.get('link_token')
|
56
68
|
account = link.find(type: 'checking_account')
|
57
69
|
|
58
|
-
# Get the
|
59
|
-
movements = account.
|
70
|
+
# Get the last 30 movements
|
71
|
+
movements = account.movements.list
|
60
72
|
|
61
73
|
# Or get all the movements since a specific date
|
62
|
-
movements = account.
|
63
|
-
|
74
|
+
movements = account.movements.list(since: '2020-08-15')
|
64
75
|
```
|
76
|
+
|
65
77
|
And that’s it!
|
66
78
|
|
79
|
+
## Client Architecture
|
80
|
+
|
81
|
+
The Fintoc Ruby client is organized into separate clients that mirror the official API structure:
|
82
|
+
|
83
|
+
### **API V1 Client**
|
84
|
+
|
85
|
+
The API client currently provides access to part of the Movements API:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
89
|
+
|
90
|
+
# Link management
|
91
|
+
links = client.v1.links.list
|
92
|
+
link = client.v1.links.get('link_token')
|
93
|
+
client.v1.links.delete('link_id')
|
94
|
+
|
95
|
+
# Account access
|
96
|
+
account = link.find(id: account_id)
|
97
|
+
```
|
98
|
+
|
99
|
+
### **API V2 Client**
|
100
|
+
|
101
|
+
The API V2 client currently provides access to part of the Transfers API:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
105
|
+
|
106
|
+
# Entities
|
107
|
+
entities = client.v2.entities.list
|
108
|
+
entity = client.v2.entities.get('entity_id')
|
109
|
+
|
110
|
+
# Transfer Accounts
|
111
|
+
accounts = client.v2.accounts.list
|
112
|
+
account = client.v2.accounts.get('account_id')
|
113
|
+
account = client.v2.accounts.create(entity_id: 'entity_id', description: 'My Account')
|
114
|
+
client.v2.accounts.update('account_id', description: 'Updated')
|
115
|
+
|
116
|
+
# Account Numbers
|
117
|
+
account_numbers = client.v2.account_numbers.list
|
118
|
+
account_number = client.v2.account_numbers.get('account_number_id')
|
119
|
+
account_number = client.v2.account_numbers.create(account_id: 'account_id', description: 'Main')
|
120
|
+
client.v2.account_numbers.update('account_number_id', description: 'Updated')
|
121
|
+
|
122
|
+
# Transfers
|
123
|
+
transfers = client.v2.transfers.list
|
124
|
+
transfer = client.v2.transfers.get('transfer_id')
|
125
|
+
transfer = client.v2.transfers.create(
|
126
|
+
amount: 1000,
|
127
|
+
currency: 'CLP',
|
128
|
+
account_id: 'account_id',
|
129
|
+
counterparty: {...}
|
130
|
+
)
|
131
|
+
client.v2.transfers.return('transfer_id')
|
132
|
+
|
133
|
+
# Simulate
|
134
|
+
simulated_transfer = client.v2.simulate.receive_transfer(
|
135
|
+
account_number_id: 'account_number_id',
|
136
|
+
amount: 1000,
|
137
|
+
currency: 'CLP'
|
138
|
+
)
|
139
|
+
|
140
|
+
# Account Verifications
|
141
|
+
account_verifications = client.v2.account_verifications.list
|
142
|
+
account_verification = client.v2.account_verifications.get('account_verification_id')
|
143
|
+
account_verification = client.v2.account_verifications.create(account_number: 'account_number')
|
144
|
+
|
145
|
+
# TODO: Movements
|
146
|
+
```
|
147
|
+
|
148
|
+
### **Backward compatibility**
|
149
|
+
|
150
|
+
The methods of the previous `Fintoc::Client` class implementation are kept for backward compatibility purposes.
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
154
|
+
|
155
|
+
link = client.get_link('link_token')
|
156
|
+
links = client.get_links
|
157
|
+
client.delete_link(link.id)
|
158
|
+
account = client.get_account('link_token', 'account_id')
|
159
|
+
```
|
160
|
+
|
67
161
|
## Documentation
|
68
162
|
|
69
|
-
This client
|
163
|
+
This client does not support all Fintoc API endpoints yet. For complete information about the API, head to the [docs](https://docs.fintoc.com/reference).
|
70
164
|
|
71
165
|
## Examples
|
72
166
|
|
73
|
-
###
|
167
|
+
### Movements API Examples
|
168
|
+
|
169
|
+
#### Get accounts
|
74
170
|
|
75
171
|
```ruby
|
76
172
|
require 'fintoc'
|
77
173
|
|
78
|
-
client = Fintoc::Client.new('api_key')
|
79
|
-
link = client.
|
174
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
175
|
+
link = client.v1.links.get('link_token')
|
80
176
|
puts link.accounts
|
81
177
|
|
82
178
|
# Or... you can pretty print all the accounts in a Link
|
83
179
|
|
84
|
-
link = client.
|
180
|
+
link = client.v1.links.get('link_token')
|
85
181
|
link.show_accounts
|
86
182
|
|
87
183
|
```
|
@@ -91,8 +187,8 @@ If you want to find a specific account in a link, you can use **find**. You can
|
|
91
187
|
```ruby
|
92
188
|
require 'fintoc'
|
93
189
|
|
94
|
-
client = Fintoc::Client.new('api_key')
|
95
|
-
link = client.
|
190
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
191
|
+
link = client.v1.links.get('link_token')
|
96
192
|
account = link.find(type: 'checking_account')
|
97
193
|
|
98
194
|
# Or by number
|
@@ -107,8 +203,8 @@ You can also search for multiple accounts matching a specific criteria with **fi
|
|
107
203
|
```ruby
|
108
204
|
require 'fintoc'
|
109
205
|
|
110
|
-
client = Fintoc::Client.new('api_key')
|
111
|
-
link = client.
|
206
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
207
|
+
link = client.v1.links.get('link_token')
|
112
208
|
accounts = link.find_all(currency: 'CLP')
|
113
209
|
```
|
114
210
|
|
@@ -117,50 +213,198 @@ To update the account balance you can use **update_balance**:
|
|
117
213
|
```ruby
|
118
214
|
require 'fintoc'
|
119
215
|
|
120
|
-
client = Fintoc::Client.new('api_key')
|
121
|
-
link = client.
|
216
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
217
|
+
link = client.v1.links.get('link_token')
|
122
218
|
account = link.find(number: '1111111')
|
123
219
|
account.update_balance
|
124
220
|
```
|
125
221
|
|
126
|
-
|
222
|
+
#### Get movements
|
127
223
|
|
128
224
|
```ruby
|
129
225
|
require 'fintoc'
|
130
226
|
require 'time'
|
131
227
|
|
132
|
-
client = Fintoc::Client.new('api_key')
|
133
|
-
link = client.
|
228
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
229
|
+
link = client.v1.links.get('link_token')
|
134
230
|
account = link.find(type: 'checking_account')
|
135
231
|
|
136
232
|
# You can get the account movements since a specific DateTime
|
137
233
|
yesterday = DateTime.now - 1
|
138
|
-
account.
|
234
|
+
account.movements.list(since: yesterday)
|
139
235
|
|
140
236
|
# Or you can use an ISO 8601 formatted string representation of the Date
|
141
|
-
account.
|
237
|
+
account.movements.list(since: '2020-01-01')
|
142
238
|
|
143
239
|
# You can also set how many movements you want per_page
|
144
|
-
account.
|
240
|
+
account.movements.list(since: '2020-01-01', per_page: 100)
|
241
|
+
```
|
242
|
+
|
243
|
+
Calling **movements.list** without arguments gets the last 30 movements of the account
|
244
|
+
|
245
|
+
### Transfers API Examples
|
246
|
+
|
247
|
+
#### Entities
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
require 'fintoc'
|
251
|
+
|
252
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
253
|
+
|
254
|
+
# Get all entities
|
255
|
+
entities = client.v2.entities.list
|
256
|
+
|
257
|
+
# Get a specific entity
|
258
|
+
entity = client.v2.entities.get('entity_id')
|
259
|
+
```
|
260
|
+
|
261
|
+
You can also list entities with pagination:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
# Get entities with pagination
|
265
|
+
entities = client.v2.entities.list(limit: 10, starting_after: 'entity_id')
|
266
|
+
```
|
267
|
+
|
268
|
+
#### Transfer Accounts
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
require 'fintoc'
|
272
|
+
|
273
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
274
|
+
|
275
|
+
# Create a transfer account
|
276
|
+
account = client.v2.accounts.create(
|
277
|
+
entity_id: 'entity_id',
|
278
|
+
description: 'My Business Account'
|
279
|
+
)
|
280
|
+
|
281
|
+
# Get a specific account
|
282
|
+
account = client.v2.accounts.get('account_id')
|
283
|
+
|
284
|
+
# List all accounts
|
285
|
+
accounts = client.v2.accounts.list
|
286
|
+
|
287
|
+
# Update an account
|
288
|
+
updated_account = client.v2.accounts.update('account_id', description: 'Updated Description')
|
289
|
+
```
|
290
|
+
|
291
|
+
#### Account Numbers
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
require 'fintoc'
|
295
|
+
|
296
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
297
|
+
|
298
|
+
# Create an account number
|
299
|
+
account_number = client.v2.account_numbers.create(
|
300
|
+
account_id: 'account_id',
|
301
|
+
description: 'Main account number'
|
302
|
+
)
|
303
|
+
|
304
|
+
# Get a specific account number
|
305
|
+
account_number = client.v2.account_numbers.get('account_number_id')
|
306
|
+
|
307
|
+
# List all account numbers
|
308
|
+
account_numbers = client.v2.account_numbers.list
|
309
|
+
|
310
|
+
# Update an account number
|
311
|
+
updated_account_number = client.v2.account_numbers.update(
|
312
|
+
'account_number_id',
|
313
|
+
description: 'Updated account number'
|
314
|
+
)
|
315
|
+
```
|
316
|
+
|
317
|
+
#### Transfers
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
require 'fintoc'
|
321
|
+
|
322
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
323
|
+
|
324
|
+
# Create a transfer
|
325
|
+
transfer = client.v2.transfers.create(
|
326
|
+
amount: 10000,
|
327
|
+
currency: 'CLP',
|
328
|
+
account_id: 'account_id',
|
329
|
+
counterparty: {
|
330
|
+
name: 'John Doe',
|
331
|
+
rut: '12345678-9',
|
332
|
+
email: 'john@example.com',
|
333
|
+
bank: 'banco_de_chile',
|
334
|
+
account_type: 'checking_account',
|
335
|
+
account_number: '1234567890'
|
336
|
+
}
|
337
|
+
)
|
338
|
+
|
339
|
+
# Get a specific transfer
|
340
|
+
transfer = client.v2.transfers.get('transfer_id')
|
341
|
+
|
342
|
+
# List all transfers
|
343
|
+
transfers = client.v2.transfers.list
|
344
|
+
|
345
|
+
# Return a transfer
|
346
|
+
returned_transfer = client.v2.transfers.return('transfer_id')
|
145
347
|
```
|
146
348
|
|
147
|
-
|
349
|
+
#### Simulate
|
350
|
+
|
351
|
+
```ruby
|
352
|
+
require 'fintoc'
|
353
|
+
|
354
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
355
|
+
|
356
|
+
# Simulate receiving a transfer
|
357
|
+
simulated_transfer = client.v2.simulate.receive_transfer(
|
358
|
+
account_number_id: 'account_number_id',
|
359
|
+
amount: 5000,
|
360
|
+
currency: 'CLP'
|
361
|
+
)
|
362
|
+
```
|
148
363
|
|
149
|
-
|
364
|
+
#### Account Verifications
|
150
365
|
|
151
|
-
|
366
|
+
```ruby
|
367
|
+
require 'fintoc'
|
152
368
|
|
153
|
-
|
154
|
-
- [**tabulate**](https://github.com/roylez/tabulate)
|
369
|
+
client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')
|
155
370
|
|
156
|
-
|
371
|
+
# Create an account verification
|
372
|
+
account_verification = client.v2.account_verifications.create(account_number: 'account_number')
|
157
373
|
|
158
|
-
|
374
|
+
# Get a specific account verification
|
375
|
+
account_verification = client.v2.account_verifications.get('account_verification_id')
|
159
376
|
|
377
|
+
# List all account verifications
|
378
|
+
account_verifications = client.v2.account_verifications.list
|
160
379
|
```
|
161
|
-
|
380
|
+
|
381
|
+
## Development
|
382
|
+
|
383
|
+
### Dependencies
|
384
|
+
|
385
|
+
This gem supports **Ruby 2.3+** but development requires modern tooling:
|
386
|
+
|
387
|
+
- **Ruby:** 2.3+ (3.2+ recommended for development)
|
388
|
+
- **Bundler:** 2.7+ (for development)
|
389
|
+
- **Git:** For version control
|
390
|
+
|
391
|
+
### Setup
|
392
|
+
|
393
|
+
```bash
|
394
|
+
# Clone the repository
|
395
|
+
git clone https://github.com/fintoc-com/fintoc-ruby.git
|
396
|
+
cd fintoc-ruby
|
397
|
+
|
398
|
+
# Install dependencies (requires Bundler 2.7+)
|
399
|
+
bundle install
|
400
|
+
|
401
|
+
# Run tests
|
402
|
+
bundle exec rspec
|
403
|
+
|
404
|
+
# Run linting
|
405
|
+
bundle exec rubocop
|
162
406
|
```
|
163
407
|
|
164
408
|
## Contributing
|
165
409
|
|
166
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/fintoc-com/fintoc.
|
410
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/fintoc-com/fintoc-ruby](https://github.com/fintoc-com/fintoc-ruby).
|
data/Rakefile
CHANGED
data/fintoc.gemspec
CHANGED
@@ -9,12 +9,13 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.summary = 'The official Ruby client for the Fintoc API.'
|
10
10
|
spec.description = 'The official Ruby client for the Fintoc API.'
|
11
11
|
spec.homepage = 'https://github.com/fintoc-com/fintoc-ruby'
|
12
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.2.2')
|
13
13
|
|
14
14
|
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
15
15
|
|
16
16
|
spec.metadata['homepage_uri'] = spec.homepage
|
17
17
|
spec.metadata['source_code_uri'] = 'https://github.com/fintoc-com/fintoc-ruby'
|
18
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
18
19
|
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
19
20
|
|
20
21
|
# Specify which files should be added to the gem when it is released.
|
@@ -26,11 +27,6 @@ Gem::Specification.new do |spec|
|
|
26
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
28
|
spec.require_paths = ['lib']
|
28
29
|
spec.add_dependency 'http'
|
30
|
+
spec.add_dependency 'money-rails'
|
29
31
|
spec.add_dependency 'tabulate'
|
30
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
31
|
-
spec.add_development_dependency 'rubocop', '~> 0.81.0'
|
32
|
-
spec.add_development_dependency 'rubocop-performance'
|
33
|
-
spec.add_development_dependency 'rubocop-rspec'
|
34
|
-
spec.add_development_dependency 'vcr'
|
35
|
-
spec.add_development_dependency 'webmock'
|
36
32
|
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'http'
|
2
|
+
require 'json'
|
3
|
+
require 'fintoc/utils'
|
4
|
+
require 'fintoc/errors'
|
5
|
+
require 'fintoc/constants'
|
6
|
+
require 'fintoc/version'
|
7
|
+
require 'fintoc/jws'
|
8
|
+
|
9
|
+
module Fintoc
|
10
|
+
class BaseClient
|
11
|
+
include Utils
|
12
|
+
|
13
|
+
attr_accessor :default_params
|
14
|
+
|
15
|
+
def initialize(api_key, jws_private_key: nil)
|
16
|
+
@api_key = api_key
|
17
|
+
@user_agent = "fintoc-ruby/#{Fintoc::VERSION}"
|
18
|
+
@headers = { Authorization: "Bearer #{@api_key}", 'User-Agent': @user_agent }
|
19
|
+
@link_headers = nil
|
20
|
+
@link_header_pattern = '<(?<url>.*)>;\s*rel="(?<rel>.*)"'
|
21
|
+
@default_params = {}
|
22
|
+
@jws = jws_private_key ? Fintoc::JWS.new(jws_private_key) : nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def get(version: :v1)
|
26
|
+
request('get', version: version)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(version: :v1)
|
30
|
+
request('delete', version: version)
|
31
|
+
end
|
32
|
+
|
33
|
+
def post(version: :v1, use_jws: false)
|
34
|
+
request('post', version: version, use_jws: use_jws)
|
35
|
+
end
|
36
|
+
|
37
|
+
def patch(version: :v1, use_jws: false)
|
38
|
+
request('patch', version: version, use_jws: use_jws)
|
39
|
+
end
|
40
|
+
|
41
|
+
def request(method, version: :v1, use_jws: false)
|
42
|
+
proc do |resource, **kwargs|
|
43
|
+
parameters = params(method, **kwargs)
|
44
|
+
response = make_request(method, resource, parameters, version: version, use_jws: use_jws)
|
45
|
+
content = JSON.parse(response.body, symbolize_names: true)
|
46
|
+
|
47
|
+
if response.status.client_error? || response.status.server_error?
|
48
|
+
raise_custom_error(content[:error])
|
49
|
+
end
|
50
|
+
|
51
|
+
@link_headers = response.headers.get('link')
|
52
|
+
content
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def fetch_next
|
57
|
+
next_ = link_headers['next']
|
58
|
+
Enumerator.new do |yielder|
|
59
|
+
while next_
|
60
|
+
yielder << get.call(next_)
|
61
|
+
next_ = link_headers['next']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
visible_chars = 8
|
68
|
+
visible_key = @api_key.slice(0, visible_chars)
|
69
|
+
hidden_part = '*' * (@api_key.size - visible_chars)
|
70
|
+
"#{self.class.name}(🔑=#{visible_key + hidden_part})"
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def client
|
76
|
+
@client ||= HTTP.headers(@headers)
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_headers(dict, link)
|
80
|
+
matches = link.strip.match(@link_header_pattern)
|
81
|
+
dict[matches[:rel]] = matches[:url]
|
82
|
+
dict
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_url(resource, version: :v1)
|
86
|
+
base_url = version == :v2 ? Fintoc::Constants::BASE_URL_V2 : Fintoc::Constants::BASE_URL
|
87
|
+
"#{Fintoc::Constants::SCHEME}#{base_url}#{resource}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def should_use_jws?(method, use_jws)
|
91
|
+
use_jws && @jws && %w[post patch put].include?(method.downcase)
|
92
|
+
end
|
93
|
+
|
94
|
+
def make_request(method, resource, parameters, version: :v1, use_jws: false)
|
95
|
+
# this is to handle url returned in the link headers
|
96
|
+
# I'm sure there is a better and more clever way to solve this
|
97
|
+
if resource.start_with? 'https'
|
98
|
+
return client.send(method, resource)
|
99
|
+
end
|
100
|
+
|
101
|
+
url = build_url(resource, version:)
|
102
|
+
|
103
|
+
if should_use_jws?(method, use_jws)
|
104
|
+
request_body = parameters[:json]&.to_json || ''
|
105
|
+
jws_signature = @jws.generate_signature(request_body)
|
106
|
+
|
107
|
+
return client.headers('Fintoc-JWS-Signature' => jws_signature).send(method, url, parameters)
|
108
|
+
end
|
109
|
+
|
110
|
+
client.send(method, url, parameters)
|
111
|
+
end
|
112
|
+
|
113
|
+
def params(method, **kwargs)
|
114
|
+
if method == 'get'
|
115
|
+
{ params: { **@default_params, **kwargs } }
|
116
|
+
else
|
117
|
+
{ json: { **@default_params, **kwargs } }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def raise_custom_error(error)
|
122
|
+
raise error_class(error[:code]).new(error[:message], error[:doc_url])
|
123
|
+
end
|
124
|
+
|
125
|
+
def error_class(snake_code)
|
126
|
+
pascal_klass_name = Utils.snake_to_pascal(snake_code)
|
127
|
+
# this conditional klass_name is to handle InternalServerError custom error class
|
128
|
+
# without this the error class name would be like InternalServerErrorError (^-^)
|
129
|
+
klass =
|
130
|
+
pascal_klass_name.end_with?('Error') ? pascal_klass_name : "#{pascal_klass_name}Error"
|
131
|
+
Module.const_get("Fintoc::Errors::#{klass}")
|
132
|
+
end
|
133
|
+
|
134
|
+
# rubocop:disable Layout/LineLength
|
135
|
+
# This attribute getter parses the link headers using some regex 24K magic in the air...
|
136
|
+
# Ex.
|
137
|
+
# <https://api.fintoc.com/v1/links?page=1>; rel="first", <https://api.fintoc.com/v1/links?page=1>; rel="last"
|
138
|
+
# this helps to handle pagination see: https://fintoc.com/docs#paginacion
|
139
|
+
# return a hash like { first:"https://api.fintoc.com/v1/links?page=1" }
|
140
|
+
#
|
141
|
+
# @param link_headers [String]
|
142
|
+
# @return [Hash]
|
143
|
+
# rubocop:enable Layout/LineLength
|
144
|
+
def link_headers
|
145
|
+
return if @link_headers.nil?
|
146
|
+
|
147
|
+
@link_headers[0].split(',').reduce({}) { |dict, link| parse_headers(dict, link) }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|