fmrest 0.13.0 → 0.15.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGELOG.md +20 -0
  4. data/README.md +116 -81
  5. metadata +18 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04e163122c2e385a1957c0c3c111a7b4f9a75cbb04aaf362544383c78b972150
4
- data.tar.gz: 2b69f8782b89ddbe4464fc7623f2abde16ccd1cdc113a56425e87a47b8b6876e
3
+ metadata.gz: a521c338828739448e5bd15308c97d5b099fe0c2684728479f93f10125d93892
4
+ data.tar.gz: 613f16988c9b1d3516088a4b699171819e6fc6531ae9bb383bdaba6074a68020
5
5
  SHA512:
6
- metadata.gz: e13a616364f5e6e5f61c4e97d27ecbef7450cf427f10fceb67d67d3dfb0394fc1e07ce27d80b1d0bf4310305b46c7fd0bd32175a1ba55aba30183334e153f72a
7
- data.tar.gz: 23e8705ed23af5cb644b7b8616abdb72a04c3bf82e01a99b0118451f0b0f35267db04ad86781d2f754c0622a0e8c6a8dc6a92a0c107375bd11f2e79c17ccf49f
6
+ metadata.gz: 148467a2ef5570c06605eb94bd2d604e3303062428f218f3c6706483e68c6ec8098b7e6c9214f219b87b10126ec73c627ca4c5ca91974dd4e323446f2436f1ae
7
+ data.tar.gz: cb382ee99672a58d215d00398a98c44be9ef840b5b9853f94edfb3c5c58c770f02245baf95545f0732c61c44342126ac314b698293622e8f1ad52aa67fb554ca
data/.yardopts CHANGED
@@ -1,4 +1,5 @@
1
1
  --markup markdown
2
2
  --plugin activesupport-concern
3
+ lib/**/*.rb
3
4
  -
4
5
  docs/*
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  ## Changelog
2
2
 
3
+ ### 0.15.2
4
+
5
+ * Fix autoloading of `FmRest::Layout`
6
+
7
+ ### 0.15.0
8
+
9
+ * Much improved querying API (see documentation on querying), adding new
10
+ `.query` capabilities, as well as two new methods: `.match` and `.or`
11
+
12
+ ### 0.14.0
13
+
14
+ * Aliased `FmRest::Spyke::Base` as `FmRest::Layout` (now preferred), and
15
+ provided a shortcut version for setting the layout name (e.g. `class Foo <
16
+ FmRest::Layout("LayoutName")`)
17
+ * Made `layout` class setting subclass-inheritable
18
+
19
+ ### 0.13.1
20
+
21
+ * Fix downloading of container field data from FMS19+
22
+
3
23
  ### 0.13.0
4
24
 
5
25
  * Split `fmrest` gem into `fmrest-core` and `fmrest-spyke`. `fmrest` becomes a
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/fmrest.svg?style=flat)](https://rubygems.org/gems/fmrest)
4
4
  ![CI](https://github.com/beezwax/fmrest-ruby/workflows/CI/badge.svg)
5
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/beezwax/fmrest-ruby)
5
6
 
6
7
  A Ruby client for
7
8
  [FileMaker 18 and 19's Data API](https://help.claris.com/en/data-api-guide)
@@ -9,7 +10,7 @@ using
9
10
  [Faraday](https://github.com/lostisland/faraday) and with optional
10
11
  ActiveRecord-ish ORM features through [Spyke](https://github.com/balvig/spyke).
11
12
 
12
- fmrest-ruby only partially implements FileMaker 18's Data API.
13
+ fmrest-ruby only partially implements FileMaker 19's Data API.
13
14
  See the [implementation completeness table](#api-implementation-completeness-table)
14
15
  to see if a feature you need is natively supported by the gem.
15
16
 
@@ -17,10 +18,10 @@ to see if a feature you need is natively supported by the gem.
17
18
 
18
19
  The `fmrest` gem is a wrapper for two other gems:
19
20
 
20
- * `fmrest-core`, which provides the core Faraday connection builder, session
21
+ * `fmrest-spyke`, providing an ActiveRecord-like ORM library built on top
22
+ of `fmrest-core` and [Spyke](https://github.com/balvig/spyke).
23
+ * `fmrest-core`, providing the core Faraday connection builder, session
21
24
  management, and other core utilities.
22
- * `fmrest-spyke`, which provides an ActiveRecord-like ORM library built on top
23
- of `fmrest-core` and Spyke.
24
25
 
25
26
  ## Installation
26
27
 
@@ -30,7 +31,7 @@ Add this to your Gemfile:
30
31
  gem 'fmrest'
31
32
  ```
32
33
 
33
- Or if you just want to use the Faraday connection without the ORM features, do:
34
+ Or if you just want to use the Faraday connection without the ORM features:
34
35
 
35
36
  ```ruby
36
37
  gem 'fmrest-core'
@@ -40,10 +41,11 @@ gem 'fmrest-core'
40
41
 
41
42
  ### ORM example
42
43
 
43
- Most people would want to use the ORM features provided by `fmrest-spyke`:
44
+ Most people would want to use the ORM features:
44
45
 
45
46
  ```ruby
46
- class Honeybee < FmRest::Spyke::Base
47
+ # A Layout model connecting to the "Honeybees Web" FileMaker layout
48
+ class Honeybee < FmRest::Layout("Honeybees Web")
47
49
  # Connection settings
48
50
  self.fmrest_config = {
49
51
  host: "…",
@@ -53,13 +55,28 @@ class Honeybee < FmRest::Spyke::Base
53
55
  }
54
56
 
55
57
  # Mapped attributes
56
- attributes name: "Bee Name", age: "Bee Age"
58
+ attributes name: "Bee Name", age: "Bee Age", created_on: "Created On"
57
59
 
58
- # Portals
59
- has_portal :flowers
60
+ # Portal associations
61
+ has_portal :tasks
60
62
 
61
- # File container
63
+ # File containers
62
64
  container :photo, field_name: "Bee Photo"
65
+
66
+ # Scopes
67
+ scope :can_legally_fly, -> { query(age: ">18") }
68
+
69
+ # Client-side validations
70
+ validates :name, presence: true
71
+
72
+ # Callbacks
73
+ before_save :set_created_on
74
+
75
+ private
76
+
77
+ def set_created_on
78
+ self.created_on = Date.today
79
+ end
63
80
  end
64
81
 
65
82
  # Find a record by id
@@ -68,7 +85,7 @@ bee = Honeybee.find(9)
68
85
  bee.name = "Hutch"
69
86
 
70
87
  # Add a new record to portal
71
- bee.flowers.build(name: "Daisy")
88
+ bee.tasks.build(urgency: "Today")
72
89
 
73
90
  bee.save
74
91
  ```
@@ -88,11 +105,11 @@ connection = FmRest::V1.build_connection(
88
105
  )
89
106
 
90
107
  # Get all records (as parsed JSON)
91
- connection.get("layouts/MyFancyLayout/records")
108
+ connection.get("layouts/FancyLayout/records")
92
109
 
93
110
  # Create new record
94
111
  connection.post do |req|
95
- req.url "layouts/MyFancyLayout/records"
112
+ req.url "layouts/FancyLayout/records"
96
113
 
97
114
  # You can just pass a hash for the JSON body
98
115
  req.body = { … }
@@ -128,9 +145,9 @@ You can also pass a `:log` option for basic request logging, see the section on
128
145
  Option | Description | Format | Default
129
146
  --------------------|--------------------------------------------|-----------------------------|--------
130
147
  `:host` | Hostname with optional port, e.g. `"example.com:9000"` | String | None
131
- `:database` | | String | None
132
- `:username` | | String | None
133
- `:password` | | String | None
148
+ `:database` | The name of the database to connect to | String | None
149
+ `:username` | A Data API-ready account | String | None
150
+ `:password` | Your password | String | None
134
151
  `:account_name` | Alias of `:username` | String | None
135
152
  `:ssl` | SSL options to be forwarded to Faraday | Faraday SSL options | None
136
153
  `:proxy` | Proxy options to be forwarded to Faraday | Faraday proxy options | None
@@ -157,8 +174,8 @@ FmRest.default_connection_settings = {
157
174
  }
158
175
  ```
159
176
 
160
- These settings will be used by default by `FmRest::Spyke::Base` models whenever
161
- you don't set `fmrest_config=` explicitly, as well as by
177
+ These settings will be used by default by `FmRest::Layout` models whenever you
178
+ don't set `fmrest_config=` explicitly, as well as by
162
179
  `FmRest::V1.build_connection` in case you're setting up your Faraday connection
163
180
  manually.
164
181
 
@@ -188,11 +205,11 @@ building REST ORM models. fmrest-ruby builds its ORM features atop Spyke,
188
205
  bundled in the `fmrest-spyke` gem (already included if you're using the
189
206
  `fmrest` gem).
190
207
 
191
- To create a model you can inherit directly from `FmRest::Spyke::Base`, which is
192
- itself a subclass of `Spyke::Base`.
208
+ To create a model you can inherit directly from `FmRest::Layout` (itself a
209
+ subclass of `Spyke::Base`).
193
210
 
194
211
  ```ruby
195
- class Honeybee < FmRest::Spyke::Base
212
+ class Honeybee < FmRest::Layout
196
213
  end
197
214
  ```
198
215
 
@@ -216,17 +233,23 @@ bee = Honeybee.find(9) # GET request
216
233
 
217
234
  It's recommended that you read Spyke's documentation for more information on
218
235
  these basic features. If you've used ActiveRecord or similar ORM libraries
219
- however you'll find it quite familiar.
236
+ you'll find it quite familiar.
220
237
 
221
- In addition, `FmRest::Spyke::Base` extends `Spyke::Base` with the following
238
+ Notice that `FmRest::Layout` is aliased as `FmRest::Spyke::Base`. Previous
239
+ versions of fmrest-ruby only provided the latter version, so if you're already
240
+ using `FmRest::Spyke::Base` there's no need to rename your classes to
241
+ `FmRest::Layout`, both will continue to work interchangeably.
242
+
243
+ In addition, `FmRest::Layout` extends `Spyke::Base` with the following
222
244
  features:
223
245
 
224
- ### Model.fmrest_config=
246
+ ### FmRest::Layout.fmrest_config=
225
247
 
226
- This allows you to set your Data API connection settings on your model:
248
+ This allows you to set Data API connection settings specific to your model
249
+ class:
227
250
 
228
251
  ```ruby
229
- class Honeybee < FmRest::Spyke::Base
252
+ class Honeybee < FmRest::Layout
230
253
  self.fmrest_config = {
231
254
  host: "…",
232
255
  database: "…",
@@ -244,9 +267,8 @@ does the initial connection setup and then inherit from it in models using that
244
267
  same connection. E.g.:
245
268
 
246
269
  ```ruby
247
- class BeeBase < FmRest::Spyke::Base
248
- self.fmrest_config = { host: "…", … }
249
- }
270
+ class BeeBase < FmRest::Layout
271
+ self.fmrest_config = { host: "…", database: "", }
250
272
  end
251
273
 
252
274
  class Honeybee < BeeBase
@@ -254,34 +276,46 @@ class Honeybee < BeeBase
254
276
  end
255
277
  ```
256
278
 
279
+ Also, if not set, your model will try to use
280
+ `FmRest.default_connection_settings` instead.
281
+
257
282
  #### Connection settings overlays
258
283
 
259
284
  There may be cases where you want to use a different set of connection settings
260
285
  depending on context. For example, if you want to use username and password
261
- provided by the user in a web application. Since `Model.fmrest_config` is set
262
- at the class level, changing the username/password for the model in one context
263
- would also change it in all other contexts, leading to security issues.
286
+ provided by the user in a web application. Since `.fmrest_config`
287
+ is set at the class level, changing the username/password for the model in one
288
+ context would also change it in all other contexts, leading to security issues.
264
289
 
265
290
  To solve this scenario, fmrest-ruby provides a way of defining thread-local and
266
- reversible connection settings overlays through `Model.fmrest_config_overlay=`.
291
+ reversible connection settings overlays through
292
+ `.fmrest_config_overlay=`.
267
293
 
268
294
  See the [main document on connection setting overlays](docs/ConfigOverlays.md)
269
295
  for details on how it works.
270
296
 
271
- ### Model.layout
297
+ ### FmRest::Layout.layout
272
298
 
273
- Use `Model.layout` to define the layout for your model.
299
+ Use `layout` to set the layout name for your model.
274
300
 
275
301
  ```ruby
276
- class Honeybee < FmRest::Spyke::Base
302
+ class Honeybee < FmRest::Layout
277
303
  layout "Honeybees Web"
278
304
  end
279
305
  ```
280
306
 
281
- Note that you only need to set this if the name of the model and the name of
282
- the layout differ, otherwise the default will just work.
307
+ Alternatively, if you're inheriting from `FmRest::Layout` directly you can set
308
+ the layout name in the class definition line:
309
+
310
+ ```ruby
311
+ class Honeybee < FmRest::Layout("Honeybees Web")
312
+ ```
313
+
314
+ Note that you only need to manually set the layout name if the name of the
315
+ class and the name of the layout differ, otherwise fmrest-ruby will just use
316
+ the name of the class.
283
317
 
284
- ### Model.request_auth_token
318
+ ### FmRest::Layout.request_auth_token
285
319
 
286
320
  Requests a Data API session token using the connection settings in
287
321
  `fmrest_config` and returns it if successful, otherwise returns `false`.
@@ -290,16 +324,16 @@ You normally don't need to use this method as fmrest-ruby will automatically
290
324
  request and store session tokens for you (provided that `:autologin` is
291
325
  `true`).
292
326
 
293
- ### Model.logout
327
+ ### FmRest::Layout.logout
294
328
 
295
- Use `Model.logout` to log out from the database session (you may call it on any
329
+ Use `.logout` to log out from the database session (you may call it on any
296
330
  model that uses the database session you want to log out from).
297
331
 
298
332
  ```ruby
299
333
  Honeybee.logout
300
334
  ```
301
335
 
302
- ### Mapped Model.attributes
336
+ ### Mapped FmRest::Layout.attributes
303
337
 
304
338
  Spyke allows you to define your model's attributes using `attributes`, however
305
339
  sometimes FileMaker's field names aren't very Ruby-ORM-friendly, especially
@@ -308,7 +342,7 @@ fmrest-ruby extends `attributes`' functionality to allow you to map
308
342
  Ruby-friendly attribute names to FileMaker field names. E.g.:
309
343
 
310
344
  ```ruby
311
- class Honeybee < FmRest::Spyke::Base
345
+ class Honeybee < FmRest::Layout
312
346
  attributes first_name: "First Name", last_name: "Last Name"
313
347
  end
314
348
  ```
@@ -327,16 +361,16 @@ bee.first_name = "Queen"
327
361
  bee.attributes # => { "First Name": "Queen", "Last Name": "Buzz" }
328
362
  ```
329
363
 
330
- ### Model.has_portal
364
+ ### FmRest::Layout.has_portal
331
365
 
332
366
  You can define portal associations on your model wth `has_portal`, as such:
333
367
 
334
368
  ```ruby
335
- class Honeybee < FmRest::Spyke::Base
369
+ class Honeybee < FmRest::Layout
336
370
  has_portal :flowers
337
371
  end
338
372
 
339
- class Flower < FmRest::Spyke::Base
373
+ class Flower < FmRest::Layout
340
374
  attributes :color, :species
341
375
  end
342
376
  ```
@@ -371,8 +405,8 @@ Guides](https://guides.rubyonrails.org/active_model_basics.html#dirty).
371
405
  Since Spyke is API-agnostic it only provides a wide-purpose `.where` method for
372
406
  passing arbitrary parameters to the REST backend. fmrest-ruby however is well
373
407
  aware of its backend API, so it extends Spkye models with a bunch of useful
374
- querying methods: `.query`, `.limit`, `.offset`, `.sort`, `.portal`, `.script`,
375
- etc.
408
+ querying methods: `.query`, `.match`, `.omit`, `.limit`, `.offset`, `.sort`,
409
+ `.portal`, `.script`, etc.
376
410
 
377
411
  See the [main document on querying](docs/Querying.md) for detailed information
378
412
  on the query API methods.
@@ -393,7 +427,7 @@ detailed information on how those work.
393
427
  You can define container fields on your model class with `container`:
394
428
 
395
429
  ```ruby
396
- class Honeybee < FmRest::Spyke::Base
430
+ class Honeybee < FmRest::Layout
397
431
  container :photo, field_name: "Beehive Photo ID"
398
432
  end
399
433
  ```
@@ -411,7 +445,7 @@ details.
411
445
 
412
446
  ### Setting global field values
413
447
 
414
- You can call `.set_globals` on any `FmRest::Spyke::Base` model to set global
448
+ You can call `.set_globals` on any `FmRest::Layout` model to set global
415
449
  field values on the database that model is configured for.
416
450
 
417
451
  See the [main document on setting global field values](docs/GlobalFields.md)
@@ -435,7 +469,7 @@ FmRest.default_connection_settings = {
435
469
  }
436
470
 
437
471
  # Or in your model
438
- class LoggyBee < FmRest::Spyke::Base
472
+ class LoggyBee < FmRest::Layout
439
473
  self.fmrest_config = {
440
474
  host: "…",
441
475
 
@@ -449,7 +483,7 @@ If you need to set up more complex logging for your models can use the
449
483
  Faraday connection, e.g.:
450
484
 
451
485
  ```ruby
452
- class LoggyBee < FmRest::Spyke::Base
486
+ class LoggyBee < FmRest::Layout
453
487
  faraday do |conn|
454
488
  conn.response :logger, MyApp.logger, bodies: true
455
489
  end
@@ -460,31 +494,31 @@ end
460
494
 
461
495
  FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
462
496
 
463
- | FM 18 Data API feature | Supported by basic connection | Supported by FmRest::Spyke::Base |
464
- |-------------------------------------|-------------------------------|----------------------------------|
465
- | Log in using HTTP Basic Auth | Yes | Yes |
466
- | Log in using OAuth | No | No |
467
- | Log in to an external data source | No | No |
468
- | Log in using a FileMaker ID account | No | No |
469
- | Log out | Yes | Yes |
470
- | Get product information | Manual* | No |
471
- | Get database names | Manual* | No |
472
- | Get script names | Manual* | No |
473
- | Get layout names | Manual* | No |
474
- | Get layout metadata | Manual* | No |
475
- | Create a record | Manual* | Yes |
476
- | Edit a record | Manual* | Yes |
477
- | Duplicate a record | Manual* | No |
478
- | Delete a record | Manual* | Yes |
479
- | Edit portal records | Manual* | Yes |
480
- | Get a single record | Manual* | Yes |
481
- | Get a range of records | Manual* | Yes |
482
- | Get container data | Manual* | Yes |
483
- | Upload container data | Manual* | Yes |
484
- | Perform a find request | Manual* | Yes |
485
- | Set global field values | Manual* | Yes |
486
- | Run a script | Manual* | Yes |
487
- | Run a script with another request | Manual* | Yes |
497
+ | FM 18 Data API feature | Supported by basic connection | Supported by FmRest::Layout |
498
+ |-------------------------------------|-------------------------------|-----------------------------|
499
+ | Log in using HTTP Basic Auth | Yes | Yes |
500
+ | Log in using OAuth | No | No |
501
+ | Log in to an external data source | No | No |
502
+ | Log in using a FileMaker ID account | No | No |
503
+ | Log out | Yes | Yes |
504
+ | Get product information | Manual* | No |
505
+ | Get database names | Manual* | No |
506
+ | Get script names | Manual* | No |
507
+ | Get layout names | Manual* | No |
508
+ | Get layout metadata | Manual* | No |
509
+ | Create a record | Manual* | Yes |
510
+ | Edit a record | Manual* | Yes |
511
+ | Duplicate a record | Manual* | No |
512
+ | Delete a record | Manual* | Yes |
513
+ | Edit portal records | Manual* | Yes |
514
+ | Get a single record | Manual* | Yes |
515
+ | Get a range of records | Manual* | Yes |
516
+ | Get container data | Manual* | Yes |
517
+ | Upload container data | Manual* | Yes |
518
+ | Perform a find request | Manual* | Yes |
519
+ | Set global field values | Manual* | Yes |
520
+ | Run a script | Manual* | Yes |
521
+ | Run a script with another request | Manual* | Yes |
488
522
 
489
523
  \* You can manually supply the URL and JSON to a `FmRest` connection.
490
524
 
@@ -496,6 +530,7 @@ the following Ruby implementations:
496
530
  * Ruby 2.5
497
531
  * Ruby 2.6
498
532
  * Ruby 2.7
533
+ * Ruby 3.0
499
534
 
500
535
  ## Gem development
501
536
 
@@ -518,6 +553,6 @@ See [LICENSE.txt](LICENSE.txt).
518
553
 
519
554
  ## Disclaimer
520
555
 
521
- This project is not sponsored by or otherwise affiliated with FileMaker, Inc,
522
- an Apple subsidiary. FileMaker is a trademark of FileMaker, Inc., registered in
523
- the U.S. and other countries.
556
+ This project is not sponsored by or otherwise affiliated with Claris
557
+ International Inc., an Apple Inc. subsidiary. FileMaker is a trademark of
558
+ Claris International Inc., registered in the U.S. and other countries.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fmrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.15.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Carbajal
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-11 00:00:00.000000000 Z
11
+ date: 2021-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fmrest-core
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.13.0
19
+ version: 0.15.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.13.0
26
+ version: 0.15.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: fmrest-spyke
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 0.13.0
33
+ version: 0.15.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 0.13.0
40
+ version: 0.15.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -222,6 +222,17 @@ licenses:
222
222
  - MIT
223
223
  metadata: {}
224
224
  post_install_message: |+
225
+ =======================================
226
+ Notes on upgrading from fmrest < 0.15
227
+ =======================================
228
+
229
+ There's a breaking change in the way the `.query` method behaves when chained.
230
+
231
+ Previously it would add new conditions as a logical OR in relation to
232
+ already set ones, whereas now by default it adds new conditions as a logical
233
+ AND relative to existing ones. To keep the old behavior you can use `.or.query`
234
+ in chained query calls instead. See documentation on querying for details.
235
+
225
236
  =======================================
226
237
  Notes on upgrading from fmrest < 0.13
227
238
  =======================================
@@ -266,7 +277,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
277
  - !ruby/object:Gem::Version
267
278
  version: '0'
268
279
  requirements: []
269
- rubygems_version: 3.2.3
280
+ rubygems_version: 3.0.6
270
281
  signing_key:
271
282
  specification_version: 4
272
283
  summary: FileMaker Data API client