configly-ruby 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +160 -12
- data/configly-ruby.gemspec +1 -1
- data/lib/configly/client.rb +35 -16
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d1525cdf4c14061d87df93eb5d7784ed7ec17a97ca73952c1b05955c22c1d89
|
4
|
+
data.tar.gz: e5e66c9d611800617304884ec26a408cd4e900f7ce559e38998e1126650098b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ccd504f03c7a4f08242b887d873d7e47588cc3fbcb7258c0dc299828b3f982724520451c0f14cd8725d0df1436a787ab9bf076b7da33c8a32ec1d9bab620931
|
7
|
+
data.tar.gz: 90e29d3e9c06d3292f9f1470275567a9bec65d3e6f157b79d223a9d811e53983848db69fb80d8c3d553ef029eeaa337acdcd8e36596592492e7ed3e2d990ccac
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Configly
|
1
|
+
# Configly Ruby Library
|
2
2
|
> The Ruby library for [Configly](https://www.config.ly): the modern config/static data key/value store.
|
3
3
|
|
4
|
-
![npm](https://img.shields.io/
|
5
|
-
![GitHub](https://img.shields.io/github/license/configly/
|
4
|
+
![npm](https://img.shields.io/gem/v/configly-ruby)
|
5
|
+
![GitHub](https://img.shields.io/github/license/configly/ruby)
|
6
6
|
|
7
7
|
Table of Contents
|
8
8
|
=================
|
@@ -38,13 +38,73 @@ read more about the benefits at [Configly](config.ly).
|
|
38
38
|
|
39
39
|
- API to fetch Strings, JSON Blobs (arrays and objects), Booleans, and Numbers from the Configly backend
|
40
40
|
- [Web interface](https://www.config.ly/config) for modifying these values without having to deploy code (we call our beloved web interface _the Configulator_).
|
41
|
-
- High availability, high-throughput, low-latency backend.
|
42
|
-
- Smart caching on the client libraries to minimize server requests.
|
41
|
+
- High availability, high-throughput, low-latency backend.
|
43
42
|
- Client libraries available in an expanding amount of languages.
|
44
43
|
|
44
|
+
### Concepts/ Data Model
|
45
|
+
- A Configly account contains a set of Configs.
|
46
|
+
- A Config is a key-value pair along with associated metadata (like TTL).
|
47
|
+
- The keys are strings.
|
48
|
+
- The values are one of the following types:
|
49
|
+
|
50
|
+
#### Types
|
51
|
+
|
52
|
+
| Type | notes | Example(s)|
|
53
|
+
|---------|----------|----------|
|
54
|
+
| string | | "I <3 Configly!" |
|
55
|
+
| number | Can be integers or decimal; _be aware some clients require you to specify which when fetching_ | 31337, 1.618 |
|
56
|
+
| boolean | only true or false | true, false |
|
57
|
+
| jsonBlob | A [JSON5](https://json5.org/) (more relaxed JSON) array or object. | ``` ["one", 5, true]```, ```{"text": "Buy now!", color: "#0F0"}``` |
|
58
|
+
|
59
|
+
##### More `jsonBlob` examples
|
60
|
+
You can make arbitrarily complex JSON structures -- _as long_ as the top level is
|
61
|
+
an object or array. This is incredibly powerful as you can send a host of data
|
62
|
+
with a single _config_:
|
63
|
+
|
64
|
+
|
65
|
+
A more complex array for a store inventory. Note that because we're using JSON5, quotes
|
66
|
+
are optional for single words.
|
67
|
+
```js
|
68
|
+
[
|
69
|
+
"Simple T-shirt",
|
70
|
+
"Basic hoodie",
|
71
|
+
{
|
72
|
+
item: "Complex T-shirt",
|
73
|
+
sizes: ['S', 'M', 'L'],
|
74
|
+
price_us_cents: [1099, 1499, 1599],
|
75
|
+
}
|
76
|
+
]
|
77
|
+
```
|
78
|
+
|
79
|
+
And a more complex object showing how you can internationalize and set style:
|
80
|
+
```js
|
81
|
+
{
|
82
|
+
"welcome_message": {
|
83
|
+
copy: {
|
84
|
+
'en': 'Welcome!',
|
85
|
+
'es': "¡Bienvenidos!",
|
86
|
+
}, style: {
|
87
|
+
color: '#0F0',
|
88
|
+
fontWeight: '700',
|
89
|
+
}
|
90
|
+
},
|
91
|
+
"buy_button" : {
|
92
|
+
copy: {
|
93
|
+
'en': 'Buy',
|
94
|
+
'es': "Comprar",
|
95
|
+
}, style: {
|
96
|
+
backgroundColor: "#F00",
|
97
|
+
border: "border-radius 10px",
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
```
|
102
|
+
|
45
103
|
## Getting Started
|
46
104
|
|
47
|
-
|
105
|
+
In four easy steps!
|
106
|
+
|
107
|
+
### 1. Get your API Key
|
48
108
|
|
49
109
|
You'll need a [Configly](https://www.config.ly) account. Registration is lightning quick—you can register via
|
50
110
|
visiting [https://www.config.ly/signup](https://www.config.ly/signup).
|
@@ -52,27 +112,115 @@ visiting [https://www.config.ly/signup](https://www.config.ly/signup).
|
|
52
112
|
After signing up, you can grab your API Key from [https://www.config.ly/register](https://www.config.ly/register).
|
53
113
|
You'll need your API Key to setup the API below.
|
54
114
|
|
55
|
-
###
|
115
|
+
### 2. Create your first Config
|
116
|
+
From [https://www.config.ly/config](https://www.config.ly/config), create a new Config via the "Add" button:
|
117
|
+
![image](https://user-images.githubusercontent.com/184923/98487495-3b42ca80-21f1-11eb-9bfc-bfd429733362.png)
|
118
|
+
|
119
|
+
Consider creating a simple `JSON Object or Array` Config called `greetings` and give it the value of:
|
120
|
+
`['hello', 'hola', '你好', 'नमस्ते']`:
|
121
|
+
|
122
|
+
[https://www.config.ly/config](https://www.config.ly/config) should look like this:
|
123
|
+
|
124
|
+
![image](https://user-images.githubusercontent.com/184923/98494454-09d6f880-220b-11eb-9ef7-36709ddc129f.png)
|
56
125
|
|
126
|
+
Be sure to save via clicking 'Send to Clients'. Now, we'll write client code to fetch this key.
|
127
|
+
|
128
|
+
### 3. Install the client library
|
129
|
+
|
130
|
+
If you're using bundler, add the following line to your project's `Gemfile`:
|
131
|
+
```sh
|
132
|
+
gem 'configly-ruby', '~> 0.0.5'
|
133
|
+
```
|
134
|
+
|
135
|
+
Or, if you're using the Gem directly from your application, you can run:
|
57
136
|
```sh
|
58
137
|
gem install configly-ruby
|
59
138
|
```
|
60
139
|
|
61
140
|
You will need to set the `CONFIGLY_API_KEY` environment variable.
|
62
141
|
|
63
|
-
###
|
142
|
+
### 4. Fetch the Config
|
143
|
+
In a Rails controller, add the following code
|
144
|
+
```ruby
|
145
|
+
def get
|
146
|
+
begin
|
147
|
+
key = Configly::Client.get(params[:key])
|
148
|
+
render plain: key
|
149
|
+
rescue Configly::KeyError
|
150
|
+
render :status => 404
|
151
|
+
end
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
Map the route, and then request it in your browser with the `key` params (e.g. `http://localhost:3000/configly?key=test1234`).
|
156
|
+
|
157
|
+
Try changing some values on [https://www.config.ly/config](https://www.config.ly/config) to confirm that
|
158
|
+
the client is getting the updates.
|
159
|
+
|
160
|
+
Congratulations you have Configly working end-to-end! Now, feel free to use Configly with all your projects!
|
161
|
+
|
162
|
+
## Configuring this library to use websockets
|
64
163
|
Coming soon...
|
65
164
|
|
66
165
|
## Usage
|
166
|
+
> The golden rule of Configly library use is: **do NOT** assign the result of a `get()`
|
167
|
+
to a long-lived variable; in order to check for new values from the server, you must call `get()`.
|
168
|
+
|
169
|
+
The package needs to be configured with your account's API key, which is available in the
|
170
|
+
[Configly Configulator](https://config.ly/config)
|
171
|
+
|
172
|
+
```
|
173
|
+
// This value is stored on the Config.ly servers.
|
174
|
+
store_catalog:
|
175
|
+
{
|
176
|
+
has_sale: true,
|
177
|
+
discount: 0.8,
|
178
|
+
items: ['T Shirt', 'Hoodie', 'Ferrari'],
|
179
|
+
price: [ 100, 250, 200000],
|
180
|
+
}
|
181
|
+
```
|
67
182
|
|
68
|
-
|
183
|
+
On the Ruby client:
|
69
184
|
|
70
185
|
```ruby
|
71
|
-
|
186
|
+
begin
|
187
|
+
catalog = Configly::Client.get(KEY)
|
188
|
+
items = catalog['items']
|
189
|
+
prices = catalog['prices']
|
190
|
+
|
191
|
+
items.each_with_index do |item, index|
|
192
|
+
Rails.logger.debug("#{item}: #{prices[index]} USD")
|
193
|
+
end
|
194
|
+
rescue Configly::KeyError
|
195
|
+
Rails.logger.error("Something went wrong")
|
196
|
+
end
|
72
197
|
```
|
73
198
|
|
74
|
-
If the key doesn't exist
|
199
|
+
Note: If the key doesn't exist, this will raise a `Configly::KeyError`
|
200
|
+
|
201
|
+
Here is an example with feature flags.
|
202
|
+
// These values are stored on the Config.ly server
|
203
|
+
```
|
204
|
+
feature1_enabled: true
|
205
|
+
feature2_enabled: false
|
206
|
+
```
|
207
|
+
|
208
|
+
On the ruby client:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
begin
|
212
|
+
if Configly::Client.get('feature1_enabled')
|
213
|
+
# Logic for feature 1
|
214
|
+
end
|
215
|
+
|
216
|
+
if Configly::Client.get('feature2_enabled')
|
217
|
+
# Logic for feature 2
|
218
|
+
end
|
219
|
+
rescue Configly::KeyError
|
220
|
+
Rails.logger.error("Something went wrong")
|
221
|
+
end
|
222
|
+
```
|
75
223
|
|
76
224
|
## License
|
77
225
|
|
78
|
-
This repository is published under the [MIT](LICENSE.md) license.
|
226
|
+
This repository is published under the [MIT](LICENSE.md) license.
|
data/configly-ruby.gemspec
CHANGED
data/lib/configly/client.rb
CHANGED
@@ -8,7 +8,7 @@ CONFIGLY_VALUE_URL = '/api/v1/value'
|
|
8
8
|
module Configly
|
9
9
|
class Client
|
10
10
|
@keys = {}
|
11
|
-
@
|
11
|
+
@ttl_expirations = {}
|
12
12
|
@use_ws = false
|
13
13
|
def self.init
|
14
14
|
@use_ws = true
|
@@ -31,7 +31,7 @@ module Configly
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def self.load_initial_data
|
34
|
-
|
34
|
+
fetch(get_keys_to_preload, false)
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.start_web_socket_client
|
@@ -62,19 +62,38 @@ module Configly
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def self.fetch(keys)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
65
|
+
def self.fetch(keys, use_ttls)
|
66
|
+
current_time = Time.now.to_i
|
67
|
+
|
68
|
+
# If we aren't using the TTLs, fetch all keys
|
69
|
+
if !use_ttls
|
70
|
+
keys_to_fetch = keys
|
71
|
+
else
|
72
|
+
# Otherwise, fetch the keys that are unfetched or expired
|
73
|
+
keys_to_fetch = []
|
74
|
+
keys.each do |key|
|
75
|
+
if !@ttl_expirations.has_key?(key) || @ttl_expirations[key] < current_time
|
76
|
+
keys_to_fetch << key
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Only actually execute the request if there are keys to fetch
|
82
|
+
if keys_to_fetch.length > 0
|
83
|
+
uri = URI("https://#{CONFIGLY_SERVER}#{CONFIGLY_VALUE_URL}?#{generate_qs(keys_to_fetch)}")
|
84
|
+
|
85
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
|
86
|
+
request = Net::HTTP::Get.new uri
|
87
|
+
request.basic_auth get_api_key, ''
|
88
|
+
response = http.request request
|
89
|
+
data = JSON.parse(response.body)['data']
|
90
|
+
data.keys.each do |key|
|
91
|
+
# Set the key and the expiration
|
92
|
+
@keys[key] = data[key]['value']
|
93
|
+
@ttl_expirations[key] = current_time + data[key]['ttl']
|
94
|
+
end
|
75
95
|
end
|
76
96
|
end
|
77
|
-
return loaded_keys
|
78
97
|
end
|
79
98
|
|
80
99
|
def self.get(key)
|
@@ -85,9 +104,9 @@ module Configly
|
|
85
104
|
raise KeyError.new(key)
|
86
105
|
end
|
87
106
|
else
|
88
|
-
|
89
|
-
if
|
90
|
-
return
|
107
|
+
fetch([key], true)
|
108
|
+
if @keys.has_key? key
|
109
|
+
return @keys[key]
|
91
110
|
else
|
92
111
|
raise KeyError.new(key)
|
93
112
|
end
|