fmrest-cloud 0.19.0.rc1
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/.yardopts +5 -0
- data/CHANGELOG.md +178 -0
- data/LICENSE.txt +21 -0
- data/README.md +586 -0
- data/lib/fmrest/cloud/auth_error_handler.rb +24 -0
- data/lib/fmrest/cloud/claris_id_token_manager.rb +74 -0
- data/lib/fmrest/cloud.rb +8 -0
- data/lib/fmrest-cloud.rb +3 -0
- metadata +80 -0
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
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
|
+
[](https://rubygems.org/gems/fmrest)
|
4
|
+

|
5
|
+
[](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
|
data/lib/fmrest/cloud.rb
ADDED
data/lib/fmrest-cloud.rb
ADDED
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: []
|