fmrest-cloud 0.19.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fdace6ff94d00d799393765c739dc33c1634c283518c19c4b7318f46adf3f7f7
4
+ data.tar.gz: 7fa1956020d4e54e658964ab33a34df571ee2d48ab085d74c832207d1e920542
5
+ SHA512:
6
+ metadata.gz: 8081823bf1d53a0760fd3384bb718a95ce994d614742efdb0cd8630a54dbd20e54191c1bd864d4613e844d1739cac915465174be5e1c8406671a46d1bbc53cfc
7
+ data.tar.gz: 65bc966479036e35c5bdc4994caed746d817e84f78c4405bcd0e5c063d02a792ca48d2881ea8f99d7aa5b7c0b6bfdedaa1cf59a90bef69e1c5e9c7808c61f0b7
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --markup markdown
2
+ --plugin activesupport-concern
3
+ lib/**/*.rb
4
+ -
5
+ docs/*
data/CHANGELOG.md ADDED
@@ -0,0 +1,178 @@
1
+ ## Changelog
2
+
3
+ ### 0.19.0
4
+
5
+ * Add native support for FileMaker cloud through the `fmrest-cloud` gem
6
+
7
+ ### 0.18.0
8
+
9
+ * Better support for portals with mismatching field qualifiers
10
+ * Better ergonomics for script execution, improved documentation
11
+ * Defining an attribute on a model that would collide with an existing method
12
+ now raises an error
13
+ * Cleared Faraday deprecation messages on authentication methods
14
+ * Handle FileMaker Cloud case where HTTP 401 Unauthorized with content-type
15
+ text/html is returned after token expiry
16
+ * Add retry option to Rescuable mixin
17
+ * Added fmrest-ruby/VERSION to User-Agent headers
18
+
19
+ ### 0.17.1
20
+
21
+ * Fixed crash when `fmid_token` is set but `username` isn't
22
+
23
+ ### 0.17.0
24
+
25
+ * Added support for Claris ID token login
26
+ * Added ability to use procs in settings
27
+ * Added `Rescuable` mixin
28
+
29
+ ### 0.16.0
30
+
31
+ * Added `FmRest.logger=`
32
+ * Handle serialization of `nil`, `true` and `false` values
33
+
34
+ ### 0.15.2
35
+
36
+ * Fixed autoloading of `FmRest::Layout`
37
+
38
+ ### 0.15.0
39
+
40
+ * Much improved querying API (see documentation on querying), adding new
41
+ `.query` capabilities, as well as two new methods: `.match` and `.or`
42
+
43
+ ### 0.14.0
44
+
45
+ * Aliased `FmRest::Spyke::Base` as `FmRest::Layout` (now preferred), and
46
+ provided a shortcut version for setting the layout name (e.g. `class Foo <
47
+ FmRest::Layout("LayoutName")`)
48
+ * Made `layout` class setting subclass-inheritable
49
+
50
+ ### 0.13.1
51
+
52
+ * Fixed downloading of container field data from FMS19+
53
+
54
+ ### 0.13.0
55
+
56
+ * Split `fmrest` gem into `fmrest-core` and `fmrest-spyke`. `fmrest` becomes a
57
+ wrapper for the two new gems.
58
+ * Fixed bug preventing connection databases with spaces in their names.
59
+ * Improved portal support with ability to delete portal records, and better
60
+ refreshing of portal records after saving the parent.
61
+ * `FmRest::Spyke::Base#__record_id` and `FmRest::Spyke::Base#__mod_id` now
62
+ always return integers if set.
63
+
64
+ ### 0.12.0
65
+
66
+ * Rename `FmRest::Spyke::Base#id=` to `FmRest::Spyke::Base#__record_id=` to
67
+ prevent clobbering of FileMaker layout-defined fields
68
+ * Removed previously deprecated `FmRest::Spyke::Base(config)` syntax
69
+ * Better yard documentation
70
+
71
+ ### 0.11.1
72
+
73
+ * Fixed a couple crashes due to missing constants
74
+
75
+ ### 0.11.0
76
+
77
+ * Added custom class for connection settings, providing indifferent access
78
+ (i.e. keys can be strings or symbols), and centralized default values and
79
+ validations
80
+ * Added `:autologin`, `:token` and `:token_store` connection settings
81
+ * Added `FmRest::Base.fmrest_config_overlay=` and related methods
82
+ * Added `FmRest::V1.request_auth_token` and
83
+ `FmRest::Spyke::Base.request_auth_token` (as well as `!`-suffixed versions
84
+ which raise exceptions on failure)
85
+
86
+ ### 0.10.1
87
+
88
+ * Fixed `URI.escape` obsolete warning messages in Ruby 2.7 by replacing it with
89
+ `URI.encode_www_form_component`
90
+ ([PR#40](https://github.com/beezwax/fmrest-ruby/pull/40))
91
+
92
+ ### 0.10.0
93
+
94
+ * Added `FmRest::StringDateAwareness` module to correct some issues when using
95
+ `FmRest::StringDate`
96
+ * Added basic timezones support
97
+ * Deprecated `class < FmRest::Spyke::Base(config_hash)` syntax in favor of
98
+ using `self.fmrest_config=`
99
+
100
+ ### 0.9.0
101
+
102
+ * Added `FmRest::Spyke::Base.set_globals`
103
+
104
+ ### 0.8.0
105
+
106
+ * Improved metadata when using `FmRest::Spyke::Model`. Metadata now uses
107
+ Struct/OpenStruct, so properties are accessible through `.property`, as well
108
+ as `[:property]`
109
+ * Added batch-finders `.find_in_batches` and `.find_each` for
110
+ * `FmRest::Spyke::Base`
111
+
112
+ ### 0.7.1
113
+
114
+ * Made sure `Model.find_one` and `Model.find_some` work without needing to call
115
+ `Model.all` in between
116
+
117
+ ### 0.7.0
118
+
119
+ * Added date coercion feature
120
+
121
+ ### 0.6.0
122
+
123
+ * Implemented session logout
124
+ ([#16](https://github.com/beezwax/fmrest-ruby/issues/16))
125
+
126
+ ### 0.5.2
127
+
128
+ * Improved support for legacy ActiveModel 4.x
129
+
130
+ ### 0.5.1
131
+
132
+ * Alias `:username` option as `:account_name` for ginjo-rfm gem
133
+ cross-compatibility
134
+
135
+ ### 0.5.0
136
+
137
+ * Much improved script execution support
138
+ ([#20](https://github.com/beezwax/fmrest-ruby/issues/20))
139
+ * Fixed bug when setting `default_limi` and trying to find a record
140
+ ([35](https://github.com/beezwax/fmrest-ruby/issues/35))
141
+
142
+ ### 0.4.1
143
+
144
+ * Prevent raising an exception when a /\_find request yields no results
145
+ ([#33](https://github.com/beezwax/fmrest-ruby/issues/33) and
146
+ [#34](https://github.com/beezwax/fmrest-ruby/issues/34))
147
+
148
+ ### 0.4.0
149
+
150
+ * Implement ability to set limit and offset for portals
151
+ * Implement disabling and requesting all portals
152
+
153
+ ### 0.3.3
154
+
155
+ * Fix encoding of paths for layouts with brackets in them (e.g. `"\[Very Ugly\]
156
+ Layout"`)
157
+ * Raise an error if `"id"` is assigned as an attribute on a model, as it's
158
+ currently a reserved method name by Spyke
159
+
160
+ ### 0.3.2
161
+
162
+ * Fixed support for ActiveSupport < 5.2
163
+ ([#27](https://github.com/beezwax/fmrest-ruby/issues/27))
164
+
165
+ ### 0.3.0
166
+
167
+ * Added Moneta token store
168
+
169
+ ### 0.2.5
170
+
171
+ * Fixed crash in `fetch_container_data` when no proxy options were set
172
+
173
+ ### 0.2.4
174
+
175
+ * Use `String#=~` instead of `String#match?` for Ruby <2.4 compatibility (Fixes
176
+ [#26](https://github.com/beezwax/fmrest-ruby/issues/26))
177
+ * Deprecated `FmRest.config` in favor of `FmRest.default_connection_settings`
178
+ * Honor Faraday SSL and proxy settings when fetching container files
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Pedro Carbajal and Beezwax Datatools, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,586 @@
1
+ # fmrest-ruby
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/fmrest.svg?style=flat)](https://rubygems.org/gems/fmrest)
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)
6
+
7
+ A Ruby client for
8
+ [FileMaker's Data API](https://help.claris.com/en/data-api-guide)
9
+ with ActiveRecord-ish ORM features.
10
+
11
+ While pretty feature-rich, fmrest-ruby doesn't yet support 100% of FileMaker
12
+ 19's Data API features. See the [implementation completeness
13
+ table](#api-implementation-completeness-table) to check if a feature you need
14
+ is natively supported by the gem.
15
+
16
+ ## Contents
17
+
18
+ * [Gems](#gems)
19
+ * [Installation](#installation)
20
+ * [Simple example](#simple-example)
21
+ * [Connection settings](#connection-settings)
22
+ * [Session token store](#session-token-store)
23
+ * [Date fields and timezones](#date-fields-and-timezones)
24
+ * [ActiveRecord-like ORM (fmrest-spyke)](#activerecord-like-orm--fmrest-spyke-)
25
+ * [Logging](#logging)
26
+ * [Gotchas](#gotchas)
27
+ * [API implementation completeness table](#api-implementation-completeness-table)
28
+ * [Supported Ruby versions](#supported-ruby-versions)
29
+
30
+ ## Gems
31
+
32
+ The `fmrest` gem is a wrapper for two other gems:
33
+
34
+ * `fmrest-spyke`, providing an ActiveRecord-like ORM library built on top
35
+ of `fmrest-core` and [Spyke](https://github.com/balvig/spyke).
36
+ * `fmrest-core`, providing the core
37
+ [Faraday](https://github.com/lostisland/faraday) connection builder, session
38
+ management, and other core utilities.
39
+
40
+ In addition, the optional `fmrest-cloud` gem adds support for FileMaker Cloud.
41
+ See the [main document on connecting to FileMaker
42
+ Cloud](docs/FileMakerCloud.md).
43
+
44
+ ## Installation
45
+
46
+ In your Gemfile:
47
+
48
+ ```ruby
49
+ gem 'fmrest'
50
+
51
+ # Optional: if your files are hosted on FileMaker Cloud
52
+ gem 'fmrest-cloud'
53
+ ```
54
+
55
+ ## Simple example
56
+
57
+ ```ruby
58
+ # A Layout model connecting to the "Honeybees Web" FileMaker layout
59
+ class Honeybee < FmRest::Layout("Honeybees Web")
60
+ # Connection settings
61
+ self.fmrest_config = {
62
+ host: "…",
63
+ database: "…",
64
+ username: "…",
65
+ password: "…"
66
+ }
67
+
68
+ # Mapped attributes
69
+ attributes name: "Bee Name", age: "Bee Age", created_on: "Created On"
70
+
71
+ # Portal associations
72
+ has_portal :tasks
73
+
74
+ # File containers
75
+ container :photo, field_name: "Bee Photo"
76
+
77
+ # Scopes
78
+ scope :can_legally_fly, -> { query(age: ">18") }
79
+
80
+ # Client-side validations
81
+ validates :name, presence: true
82
+
83
+ # Callbacks
84
+ before_save :set_created_on
85
+
86
+ private
87
+
88
+ def set_created_on
89
+ self.created_on = Date.today
90
+ end
91
+ end
92
+
93
+ # Find a record by id
94
+ bee = Honeybee.find(9)
95
+
96
+ bee.name = "Hutch"
97
+
98
+ # Add a new record to portal
99
+ bee.tasks.build(urgency: "Today")
100
+
101
+ bee.save
102
+ ```
103
+
104
+ In case you don't want the ORM features (i.e. you only need authentication and
105
+ JSON parsing, and are comfortable writing the API requests manually without the
106
+ ORM overhead) you can use the Faraday connection provided by `fmrest-core`.
107
+ See the [main document on using the base
108
+ connection](docs/BaseConnectionUsage.md) for more.
109
+
110
+ ## Connection settings
111
+
112
+ The minimum required connection settings are `:host`, `:database`, `:username`
113
+ and `:password`, but fmrest-ruby has many other options you can pass when
114
+ setting up a connection (see [full list](#full-list-of-available-options) below).
115
+
116
+ `:ssl` and `:proxy` are forwarded to the underlying
117
+ [Faraday](https://github.com/lostisland/faraday) connection. You can use this
118
+ to, for instance, disable SSL verification:
119
+
120
+ ```ruby
121
+ {
122
+ host: "…",
123
+
124
+ ssl: { verify: false }
125
+ }
126
+ ```
127
+
128
+ You can also pass a `:log` option for basic request logging, see the section on
129
+ [Logging](#Logging) below.
130
+
131
+ ### Full list of available options
132
+
133
+ Option | Description | Format | Default
134
+ --------------------|--------------------------------------------|-----------------------------|--------
135
+ `:host` | Hostname with optional port, e.g. `"example.com:9000"` | String | None
136
+ `:database` | The name of the database to connect to | String | None
137
+ `:username` | A Data API-ready account | String | None
138
+ `:password` | Your password | String | None
139
+ `:account_name` | Alias of `:username` | String | None
140
+ `:ssl` | SSL options to be forwarded to Faraday | Faraday SSL options | None
141
+ `:proxy` | Proxy options to be forwarded to Faraday | Faraday proxy options | None
142
+ `:log` | Log JSON responses to STDOUT | Boolean | `false`
143
+ `:log_level` | Which log level to log into | Values accepted by `Logger#level=` | `:debug`
144
+ `:coerce_dates` | See section on [date fields](#date-fields-and-timezones) | Boolean \| `:hybrid` \| `:full` | `false`
145
+ `:date_format` | Date parsing format | String (FM date format) | `"MM/dd/yyyy"`
146
+ `:timestamp_format` | Timestmap parsing format | String (FM date format) | `"MM/dd/yyyy HH:mm:ss"`
147
+ `:time_format` | Time parsing format | String (FM date format) | `"HH:mm:ss"`
148
+ `:timezone` | The timezone for the FM server | `:local` \| `:utc` \| `nil` | `nil`
149
+ `:autologin` | Whether to automatically start Data API sessions | Boolean | `true`
150
+ `:token` | Used to manually provide a session token (e.g. if `:autologin` is `false`) | String | None
151
+ `:fmid_token` | Claris ID token (only needed if manually obtaining the token) | String | None
152
+ `:cloud` | Specifies whether the host is using FileMaker Cloud | `:auto` \| Boolean | `:auto`
153
+ `:cognito_client_id`| Overwrites the hardcoded FileMaker Cloud Cognito Client ID | String | None
154
+ `:cognito_pool_id` | Overwrites the hardcoded FileMaker Cloud Cognito Pool ID | String | None
155
+ `:aws_region` | Overwrites the hardcoded FileMaker Cloud AWS Region | String | None
156
+
157
+ ### Default connection settings
158
+
159
+ If you're only connecting to a single FM database you can configure it globally
160
+ through `FmRest.default_connection_settings=`. E.g.:
161
+
162
+ ```ruby
163
+ FmRest.default_connection_settings = {
164
+ host: "…",
165
+ database: "…",
166
+ username: "…",
167
+ password: "…"
168
+ }
169
+ ```
170
+
171
+ These settings will be used by default by `FmRest::Layout` models whenever you
172
+ don't set `fmrest_config=` explicitly, as well as by
173
+ `FmRest::V1.build_connection` in case you're setting up your Faraday connection
174
+ manually.
175
+
176
+ ## Session token store
177
+
178
+ fmrest-ruby includes a number of options for storing session tokens:
179
+
180
+ * Memory
181
+ * ActiveRecord
182
+ * Redis
183
+ * Moneta
184
+
185
+ See the [main document on token stores](docs/TokenStore.md) for detailed info
186
+ on how to set up each store.
187
+
188
+ ## Date fields and timezones
189
+
190
+ fmrest-ruby has automatic detection and coercion of date fields to and from
191
+ Ruby date/time objects. Basic timezone support is also provided.
192
+
193
+ See the [main document on date fields](docs/DateFields.md) for more info.
194
+
195
+ ## ActiveRecord-like ORM (fmrest-spyke)
196
+
197
+ [Spyke](https://github.com/balvig/spyke) is an ActiveRecord-like gem for
198
+ building REST ORM models. fmrest-ruby uses it to build its ORM features,
199
+ bundled in the `fmrest-spyke` gem (already included if you're using the
200
+ `fmrest` gem).
201
+
202
+ To create a model you can inherit directly from `FmRest::Layout` (itself a
203
+ subclass of `Spyke::Base`).
204
+
205
+ ```ruby
206
+ class Honeybee < FmRest::Layout
207
+ end
208
+ ```
209
+
210
+ All of Spyke's basic ORM operations work as expected:
211
+
212
+ ```ruby
213
+ bee = Honeybee.new
214
+
215
+ bee.name = "Hutch"
216
+ bee.save # POST request (creates new record)
217
+
218
+ bee.name = "ハッチ"
219
+ bee.save # PATCH request (updates existing record)
220
+
221
+ bee.reload # GET request
222
+
223
+ bee.destroy # DELETE request
224
+
225
+ bee = Honeybee.find(9) # GET request
226
+ ```
227
+
228
+ It's recommended that you read Spyke's documentation for more information on
229
+ these basic features. If you've used ActiveRecord or similar ORM libraries
230
+ you'll find it quite familiar.
231
+
232
+ Notice that `FmRest::Layout` is aliased as `FmRest::Spyke::Base`. Previous
233
+ versions of fmrest-ruby only provided the latter version, so if you're already
234
+ using `FmRest::Spyke::Base` there's no need to rename your classes to
235
+ `FmRest::Layout`, both will continue to work interchangeably.
236
+
237
+ In addition, `FmRest::Layout` extends `Spyke::Base` with the following
238
+ features:
239
+
240
+ ### FmRest::Layout.fmrest_config=
241
+
242
+ This allows you to set Data API connection settings specific to your model
243
+ class:
244
+
245
+ ```ruby
246
+ class Honeybee < FmRest::Layout
247
+ self.fmrest_config = {
248
+ host: "…",
249
+ database: "…",
250
+ username: "…",
251
+ password: "…"
252
+ }
253
+ end
254
+ ```
255
+
256
+ These settings are class-inheritable, so you could create a base class that
257
+ does the initial connection setup and then inherit from it in models using that
258
+ same connection. E.g.:
259
+
260
+ ```ruby
261
+ class ApplicationFmLayout < FmRest::Layout
262
+ self.fmrest_config = { host: "…", database: "…", … }
263
+ end
264
+
265
+ class Honeybee < ApplicationFmLayout
266
+ # This model will use the same connection as ApplicationFmLayout
267
+ end
268
+ ```
269
+
270
+ If `fmrest_config` is not set, your model will try to use
271
+ `FmRest.default_connection_settings` instead.
272
+
273
+ #### Connection settings overlays
274
+
275
+ There may be cases where you want to use a different set of connection settings
276
+ depending on context. For example, if you want to use username and password
277
+ provided by the user in a web application. Since `.fmrest_config` is set at the
278
+ class level, changing the username/password for the model in one context would
279
+ also change it in all other contexts, leading to security issues.
280
+
281
+ To solve this scenario, fmrest-ruby provides a way of defining thread-local,
282
+ reversible connection settings overlays through `.fmrest_config_overlay=`.
283
+
284
+ See the [main document on connection setting overlays](docs/ConfigOverlays.md)
285
+ for details on how it works.
286
+
287
+ ### FmRest::Layout.layout
288
+
289
+ Use `layout` to set the layout name for your model.
290
+
291
+ ```ruby
292
+ class Honeybee < FmRest::Layout
293
+ layout "Honeybees Web"
294
+ end
295
+ ```
296
+
297
+ Alternatively, if you're inheriting from `FmRest::Layout` directly you can set
298
+ the layout name in the class definition line:
299
+
300
+ ```ruby
301
+ class Honeybee < FmRest::Layout("Honeybees Web")
302
+ ```
303
+
304
+ Note that you only need to manually set the layout name if the name of the
305
+ class and the name of the layout differ, otherwise fmrest-ruby will just use
306
+ the name of the class.
307
+
308
+ ### FmRest::Layout.request_auth_token
309
+
310
+ Requests a Data API session token using the connection settings in
311
+ `fmrest_config` and returns it if successful, otherwise returns `false`.
312
+
313
+ You normally don't need to use this method as fmrest-ruby will automatically
314
+ request and store session tokens for you (provided that `:autologin` is
315
+ `true` in the connection settings, which it is by default).
316
+
317
+ ### FmRest::Layout.logout
318
+
319
+ Use `.logout` to log out from the database session (you may call it on any
320
+ model that uses the database session you want to log out from).
321
+
322
+ ```ruby
323
+ Honeybee.logout
324
+ ```
325
+
326
+ ### Mapped FmRest::Layout.attributes
327
+
328
+ Spyke allows you to define your model's attributes using `attributes`, however
329
+ sometimes FileMaker's field names aren't very Ruby-ORM-friendly, especially
330
+ since they may sometimes contain spaces and other special characters, so
331
+ fmrest-ruby extends `attributes`' functionality to allow you to map
332
+ Ruby-friendly attribute names to FileMaker field names. E.g.:
333
+
334
+ ```ruby
335
+ class Honeybee < FmRest::Layout
336
+ attributes first_name: "First Name", last_name: "Last Name"
337
+ end
338
+ ```
339
+
340
+ You can then simply use the pretty attribute names whenever working with your
341
+ model and they will get mapped to their FileMaker fields:
342
+
343
+ ```ruby
344
+ bee = Honeybee.find(1)
345
+
346
+ bee.first_name # => "Princess"
347
+ bee.last_name # => "Buzz"
348
+
349
+ bee.first_name = "Queen"
350
+
351
+ bee.attributes # => { "First Name": "Queen", "Last Name": "Buzz" }
352
+ ```
353
+
354
+ ### FmRest::Layout.has_portal
355
+
356
+ You can define portal associations on your model wth `has_portal`, as such:
357
+
358
+ ```ruby
359
+ class Honeybee < FmRest::Layout
360
+ has_portal :flowers
361
+ end
362
+
363
+ class Flower < FmRest::Layout
364
+ attributes :color, :species
365
+ end
366
+ ```
367
+
368
+ See the [main document on portal associations](docs/Portals.md) for details.
369
+
370
+ ### Dirty attributes
371
+
372
+ fmrest-ruby includes support for ActiveModel's Dirty mixin out of the box,
373
+ providing methods like:
374
+
375
+ ```ruby
376
+ bee = Honeybee.new
377
+
378
+ bee.changed? # => false
379
+
380
+ bee.name = "Maya"
381
+
382
+ bee.changed? # => true
383
+
384
+ bee.name_changed? # => true
385
+ ```
386
+
387
+ fmrest-ruby uses the Dirty functionality to only send changed attributes back
388
+ to the server on save.
389
+
390
+ You can read more about [ActiveModel's Dirty in Rails
391
+ Guides](https://guides.rubyonrails.org/active_model_basics.html#dirty).
392
+
393
+ ### Query API
394
+
395
+ Since Spyke is API-agnostic it only provides a wide-purpose `.where` method for
396
+ passing arbitrary parameters to the REST backend. fmrest-ruby however is well
397
+ aware of its backend API, so it extends Spkye models with a bunch of useful
398
+ querying methods: `.query`, `.match`, `.omit`, `.limit`, `.offset`, `.sort`,
399
+ `.portal`, `.script`, etc.
400
+
401
+ See the [main document on querying](docs/Querying.md) for detailed information
402
+ on the query API methods.
403
+
404
+ ### Finding records in batches
405
+
406
+ Sometimes you want to iterate over a very large number of records to do some
407
+ processing, but requesting them all at once would result in one huge request to
408
+ the Data API, and loading too many records in memory all at once.
409
+
410
+ To mitigate this problem you can use `.find_in_batches` and `.find_each`.
411
+
412
+ See the [main document on finding in batches](docs/FindInBatches.md) for
413
+ detailed information on how those work.
414
+
415
+ ### Container fields
416
+
417
+ You can define container fields on your model class with `container`:
418
+
419
+ ```ruby
420
+ class Honeybee < FmRest::Layout
421
+ container :photo, field_name: "Beehive Photo ID"
422
+ end
423
+ ```
424
+
425
+ See the [main document on container fields](docs/ContainerFields.md) for
426
+ details on how to use it.
427
+
428
+ ### Script execution
429
+
430
+ The FM Data API allows running scripts as part of many types of requests, and
431
+ `fmrest-spyke` provides mechanisms for all of them.
432
+
433
+ See the [main document on script execution](docs/ScriptExecution.md) for
434
+ details.
435
+
436
+ ### Setting global field values
437
+
438
+ You can call `.set_globals` on any `FmRest::Layout` model to set global
439
+ field values on the database that model is configured for.
440
+
441
+ See the [main document on setting global field values](docs/GlobalFields.md)
442
+ for details.
443
+
444
+ ### Rescuable mixin
445
+
446
+ Sometimes you may want to handle Data API errors at the model level. For such
447
+ cases fmrest-ruby provides an off-by-default mixin called `Rescuable` that
448
+ provides convenience macros for that. If you've used Ruby on Rails you may be
449
+ familiar with its syntax from controllers. E.g.
450
+
451
+ ```ruby
452
+ class BeeBase < FmRest::Layout
453
+ include FmRest::Spyke::Model::Rescuable
454
+
455
+ rescue_from FmRest::APIError::SystemError, with: :notify_admin_of_system_error
456
+
457
+ def self.notify_admin_of_system_error(e)
458
+ # Shoot an email to the FM admin...
459
+ end
460
+ end
461
+ ```
462
+
463
+ Since `Rescuable` uses `ActiveSupport::Rescuable` internally, you may want to
464
+ check [Rails'
465
+ documentation](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)
466
+ too for details on how it works.
467
+
468
+ One caveat of using `rescue_from` is that it always catches exceptions at the
469
+ class level, so if you pass a method name to `with:` that method has to be a
470
+ class method. Also note that this will only catch exceptions raised during an
471
+ API call to the Data API server (in other words, only on actions that perform
472
+ an HTTP request).
473
+
474
+ ## Logging
475
+
476
+ If using `fmrest-spyke` with Rails then pretty log output will be set up for
477
+ you automatically by Spyke (see [their
478
+ README](https://github.com/balvig/spyke#log-output)).
479
+
480
+ You can also enable simple Faraday logging of raw requests (useful for
481
+ debugging) by passing `log: true` in the options hash for either
482
+ `FmRest.default_connection_settings=` or your models' `fmrest_config=`, e.g.:
483
+
484
+ ```ruby
485
+ FmRest.default_connection_settings = {
486
+ host: "…",
487
+
488
+ log: true
489
+ }
490
+
491
+ # Or in your model
492
+ class LoggyBee < FmRest::Layout
493
+ self.fmrest_config = {
494
+ host: "…",
495
+
496
+ log: true
497
+ }
498
+ end
499
+ ```
500
+
501
+ You can also pass `log_level` to connection settings to change the severity of
502
+ log output (defaults to `:debug`).
503
+
504
+ By default fmrest-ruby logs to STDOUT or to Rails' logger object if available.
505
+ You can change this by providing your own logger object to `FmRest.logger=`:
506
+
507
+ ```ruby
508
+ FmRest.logger = Logger.new("fmrest.log")
509
+ ```
510
+
511
+ If you need to set up more complex logging for your models you can use the
512
+ `faraday` block inside your class to inject your own logger middleware into the
513
+ Faraday connection, e.g.:
514
+
515
+ ```ruby
516
+ class LoggyBee < FmRest::Layout
517
+ faraday do |conn|
518
+ conn.response :logger, MyApp.logger, bodies: true
519
+ end
520
+ end
521
+ ```
522
+
523
+ ## Gotchas
524
+
525
+ Read about unexpected scenarios in the [gotchas doc](docs/Gotchas.md).
526
+
527
+ ## API implementation completeness table
528
+
529
+ FM Data API reference: https://help.claris.com/en/data-api-guide/
530
+
531
+ | FM 19 Data API feature | Supported by basic connection | Supported by FmRest::Layout |
532
+ |-------------------------------------|-------------------------------|-----------------------------|
533
+ | Log in using HTTP Basic Auth | Yes | Yes |
534
+ | Log in using OAuth | No | No |
535
+ | Log in to an external data source | No | No |
536
+ | Log in using Claris ID account (FileMaker Cloud) | Yes | Yes |
537
+ | Log out | Yes | Yes |
538
+ | Get product information | Manual* | No |
539
+ | Get database names | Manual* | No |
540
+ | Get script names | Manual* | No |
541
+ | Get layout names | Manual* | No |
542
+ | Get layout metadata | Manual* | No |
543
+ | Create a record | Manual* | Yes |
544
+ | Edit a record | Manual* | Yes |
545
+ | Duplicate a record | Manual* | No |
546
+ | Delete a record | Manual* | Yes |
547
+ | Edit portal records | Manual* | Yes |
548
+ | Get a single record | Manual* | Yes |
549
+ | Get a range of records | Manual* | Yes |
550
+ | Get container data | Manual* | Yes |
551
+ | Upload container data | Manual* | Yes |
552
+ | Perform a find request | Manual* | Yes |
553
+ | Set global field values | Manual* | Yes |
554
+ | Run a script | Manual* | Yes |
555
+ | Run a script with another request | Manual* | Yes |
556
+
557
+ \* You can manually supply the URL and JSON to a `FmRest` connection.
558
+
559
+ ## Supported Ruby versions
560
+
561
+ fmrest-ruby aims to support and is [tested against](https://github.com/beezwax/fmrest-ruby/actions?query=workflow%3ACI)
562
+ the following Ruby implementations:
563
+
564
+ * Ruby 2.5
565
+ * Ruby 2.6
566
+ * Ruby 2.7
567
+ * Ruby 3.0
568
+
569
+ ## Gem development
570
+
571
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
572
+ `bundle exec rspec` to run the specs. You can also run `bin/console` for an
573
+ interactive prompt that will allow you to experiment (it will auto-load all
574
+ fixtures in spec/fixtures).
575
+
576
+ To install all gems onto your local machine, run
577
+ `bundle exec rake all:install`. To release a new version, update the version
578
+ number in `lib/fmrest/version.rb`, and then run `bundle exec rake all:release`,
579
+ which will create a git tag for the version, push git commits and tags, and
580
+ push the `.gem` files to [rubygems.org](https://rubygems.org).
581
+
582
+ ## Disclaimer
583
+
584
+ This project is not sponsored by or otherwise affiliated with Claris
585
+ International Inc., an Apple Inc. subsidiary. FileMaker is a trademark of
586
+ Claris International Inc., registered in the U.S. and other countries.
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FmRest
4
+ module Cloud
5
+ class AuthErrorHandler < Faraday::Middleware
6
+ def initialize(app, settings)
7
+ super(app)
8
+ @settings = settings
9
+ end
10
+
11
+ def call(env)
12
+ request_body = env[:body] # After failure env[:body] is set to the response body
13
+ @app.call(env)
14
+ rescue APIError::AccountError => e
15
+ ClarisIdTokenManager.new(@settings).expire_token
16
+ # Faraday::Request::Authorization will not get a new token if the
17
+ # Authorization header is already set
18
+ env.request_headers.delete("Authorization")
19
+ env[:body] = request_body
20
+ @app.call(env)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-cognito-srp"
4
+
5
+ module FmRest
6
+ module Cloud
7
+ class ClarisIdTokenManager
8
+ include TokenStore
9
+
10
+ COGNITO_CLIENT_ID = "4l9rvl4mv5es1eep1qe97cautn"
11
+ COGNITO_POOL_ID = "us-west-2_NqkuZcXQY"
12
+ AWS_REGION = "us-west-2"
13
+
14
+ TOKEN_STORE_PREFIX = "claris-cognito"
15
+
16
+ def initialize(settings)
17
+ @settings = settings
18
+ end
19
+
20
+ def fetch_token
21
+ if token = token_store.load(token_store_key)
22
+ return token
23
+ end
24
+
25
+ tokens = get_cognito_tokens
26
+
27
+ token_store.store(token_store_key, tokens.id_token)
28
+ token_store.store(token_store_key(:refresh), tokens.refresh_token) if tokens.refresh_token
29
+
30
+ tokens.id_token
31
+ end
32
+
33
+ def expire_token
34
+ token_store.delete(token_store_key)
35
+ end
36
+
37
+ private
38
+
39
+ def get_cognito_tokens
40
+ # Use refresh mechanism first if we have a refresh token
41
+ refresh_cognito_token || cognito_srp_client.authenticate
42
+ end
43
+
44
+ def refresh_cognito_token
45
+ return unless refresh_token = token_store.load(token_store_key(:refresh))
46
+
47
+ begin
48
+ cognito_srp_client.refresh_tokens(refresh_token)
49
+ rescue Aws::CognitoIdentityProvider::Errors::NotAuthorizedException
50
+ nil
51
+ end
52
+ end
53
+
54
+ def cognito_srp_client
55
+ @cognito_srp_client ||=
56
+ Aws::CognitoSrp.new(
57
+ username: @settings.username!,
58
+ password: @settings.password!,
59
+ pool_id: @settings.cognito_pool_id || COGNITO_POOL_ID,
60
+ client_id: @settings.cognito_client_id || COGNITO_CLIENT_ID,
61
+ aws_client: Aws::CognitoIdentityProvider::Client.new(region: @settings.aws_region || AWS_REGION)
62
+ )
63
+ end
64
+
65
+ def token_store_key(token_type = :id)
66
+ "#{TOKEN_STORE_PREFIX}:#{token_type}:#{@settings.username!}"
67
+ end
68
+
69
+ def token_store_option
70
+ @settings.token_store || FmRest.token_store
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FmRest
4
+ module Cloud
5
+ autoload :ClarisIdTokenManager, "fmrest/cloud/claris_id_token_manager"
6
+ autoload :AuthErrorHandler, "fmrest/cloud/auth_error_handler"
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fmrest/cloud"
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fmrest-cloud
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.19.0.rc1
5
+ platform: ruby
6
+ authors:
7
+ - Pedro Carbajal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fmrest-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.19.0.rc1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.19.0.rc1
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-cognito-srp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.4.0
41
+ description: fmrest-cloud adds FileMaker Cloud (Cognito auth) support to the fmrest
42
+ gem.
43
+ email:
44
+ - pedro_c@beezwax.net
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".yardopts"
50
+ - CHANGELOG.md
51
+ - LICENSE.txt
52
+ - README.md
53
+ - lib/fmrest-cloud.rb
54
+ - lib/fmrest/cloud.rb
55
+ - lib/fmrest/cloud/auth_error_handler.rb
56
+ - lib/fmrest/cloud/claris_id_token_manager.rb
57
+ homepage: https://github.com/beezwax/fmrest-ruby
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">"
73
+ - !ruby/object:Gem::Version
74
+ version: 1.3.1
75
+ requirements: []
76
+ rubygems_version: 3.2.3
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: FileMaker Cloud support for fmrest gem
80
+ test_files: []