web_function 0.5.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +435 -14
- data/exe/wfn +12 -5
- data/lib/web_function/argument.rb +81 -65
- data/lib/web_function/attribute.rb +78 -65
- data/lib/web_function/client.rb +119 -37
- data/lib/web_function/documented_error.rb +47 -19
- data/lib/web_function/endpoint.rb +181 -171
- data/lib/web_function/flaggable.rb +40 -0
- data/lib/web_function/object_schema.rb +135 -0
- data/lib/web_function/package.rb +169 -40
- data/lib/web_function/pipeline.rb +35 -6
- data/lib/web_function/promise.rb +68 -0
- data/lib/web_function/request.rb +172 -0
- data/lib/web_function/type/any.rb +48 -0
- data/lib/web_function/type/array_of.rb +58 -0
- data/lib/web_function/type/base.rb +89 -0
- data/lib/web_function/type/union.rb +54 -0
- data/lib/web_function/type.rb +140 -0
- data/lib/web_function/utils.rb +67 -0
- data/lib/web_function/version.rb +1 -1
- data/lib/web_function.rb +23 -11
- metadata +38 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f6b3fc6e012055cb40b8d2e51d4118b0d6d6cff8fdb62abde22790774cf787d
|
|
4
|
+
data.tar.gz: 6f795bf7794369f8fa4699c31f50af7c768b2fbd287069f3d3aca29c2da89174
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57b90f3d4d8205511ee78a0b963b35a72a535681ddb5cb6d53d942f1429222f55d8e51f48c04ee4278cb75f8766b4f3b805988e5e55c94fa0aacf14d0a803b61
|
|
7
|
+
data.tar.gz: 1c71b7c581ecfd14435c1b57251d10c8bb4199ae82b5c0d1b88e41ff85afcc072faea3b968e6f1441379740de4cd904d65414fb71eb9ac4aff93184178592a8a
|
data/README.md
CHANGED
|
@@ -1,39 +1,460 @@
|
|
|
1
|
-
#
|
|
1
|
+
# web_function
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A [Web Function](https://webfunction.org) client for Ruby.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Web Function is a way to design APIs. There are no verbs and no nested URLs. You
|
|
6
|
+
call an endpoint with a POST request, the path names the action, and the JSON
|
|
7
|
+
body carries the data. This gem lets you call those endpoints from Ruby.
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
client = WebFunction::Client.from_package_endpoint("https://api.example.com/package")
|
|
11
|
+
|
|
12
|
+
client.find_user(id: "123")
|
|
13
|
+
# => { "id" => "123", "name" => "Ada" }
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Table of contents
|
|
17
|
+
|
|
18
|
+
- [Why Web Function](#why-web-function)
|
|
19
|
+
- [Installation](#installation)
|
|
20
|
+
- [Quick start](#quick-start)
|
|
21
|
+
- [Clients](#clients)
|
|
22
|
+
- [Calling endpoints](#calling-endpoints)
|
|
23
|
+
- [Authentication](#authentication)
|
|
24
|
+
- [Versioning](#versioning)
|
|
25
|
+
- [Inspecting a package](#inspecting-a-package)
|
|
26
|
+
- [Error handling](#error-handling)
|
|
27
|
+
- [Pipelining](#pipelining)
|
|
28
|
+
- [Custom HTTP client](#custom-http-client)
|
|
29
|
+
- [Low-level requests](#low-level-requests)
|
|
30
|
+
- [Command line tool](#command-line-tool)
|
|
31
|
+
- [Development](#development)
|
|
32
|
+
- [Contributing](#contributing)
|
|
33
|
+
- [License](#license)
|
|
34
|
+
|
|
35
|
+
## Why Web Function
|
|
36
|
+
|
|
37
|
+
A Web Function API has a few simple rules:
|
|
38
|
+
|
|
39
|
+
- Every call is an HTTP POST.
|
|
40
|
+
- The request body is a JSON object.
|
|
41
|
+
- The response body is any JSON value.
|
|
42
|
+
- A `200` status means success and the body is the return value.
|
|
43
|
+
- A `400` status means the request was bad and the body explains why.
|
|
44
|
+
- Any other status is an error you handle yourself.
|
|
45
|
+
|
|
46
|
+
On top of that, an API can publish a **package**. A package is a JSON document
|
|
47
|
+
that lists the endpoints, their arguments, their return types, and their docs.
|
|
48
|
+
This gem reads a package and gives you a client that calls those endpoints as if
|
|
49
|
+
they were Ruby methods.
|
|
50
|
+
|
|
51
|
+
You can read the full specification at [webfunction.org](https://webfunction.org).
|
|
6
52
|
|
|
7
53
|
## Installation
|
|
8
54
|
|
|
9
|
-
|
|
55
|
+
Add the gem to your project:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
bundle add web_function
|
|
59
|
+
```
|
|
10
60
|
|
|
11
|
-
|
|
61
|
+
Or install it on its own:
|
|
12
62
|
|
|
13
63
|
```bash
|
|
14
|
-
|
|
64
|
+
gem install web_function
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The gem needs Ruby 3.1 or newer.
|
|
68
|
+
|
|
69
|
+
## Quick start
|
|
70
|
+
|
|
71
|
+
Point a client at a package URL and start calling endpoints:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
require "web_function"
|
|
75
|
+
|
|
76
|
+
client = WebFunction::Client.from_package_endpoint("https://api.example.com/package")
|
|
77
|
+
|
|
78
|
+
# An endpoint named "list-items" becomes the method "list_items".
|
|
79
|
+
items = client.list_items(limit: 10)
|
|
80
|
+
# => [{ "id" => 1 }, { "id" => 2 }]
|
|
81
|
+
|
|
82
|
+
# Pass a bearer token for endpoints that need authentication.
|
|
83
|
+
secure = WebFunction::Client.from_package_endpoint(
|
|
84
|
+
"https://api.example.com/package",
|
|
85
|
+
bearer_auth: "my-token",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
secure.create_item(name: "Notebook")
|
|
89
|
+
# => { "id" => 3, "name" => "Notebook" }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Clients
|
|
93
|
+
|
|
94
|
+
A `WebFunction::Client` wraps a package and turns each endpoint into a method.
|
|
95
|
+
|
|
96
|
+
You usually build a client from a package URL. The gem fetches the package,
|
|
97
|
+
reads its endpoints, and returns a ready client:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
client = WebFunction::Client.from_package_endpoint("https://api.example.com/package")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
If you already have a package in memory, build the client from that instead.
|
|
104
|
+
This avoids the extra request:
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
package = WebFunction::Package.from_hash(
|
|
108
|
+
"base_url" => "https://api.example.com/",
|
|
109
|
+
"endpoints" => [
|
|
110
|
+
{ "name" => "list-items" },
|
|
111
|
+
{ "name" => "create-item" },
|
|
112
|
+
],
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
client = WebFunction::Client.from_package(package)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Both builders accept the same options:
|
|
119
|
+
|
|
120
|
+
| Option | Description |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| `bearer_auth` | A bearer token sent with every call. |
|
|
123
|
+
| `version` | A version string sent in the `Api-Version` header. |
|
|
124
|
+
| `pipelined` | When `true`, calls are batched into one request. See [Pipelining](#pipelining). |
|
|
125
|
+
|
|
126
|
+
You can also overwrite these using the `Client#bearer_auth=`, `Client#version=`
|
|
127
|
+
and `Client#pipeline=` attribute writers after having instantiated a client.
|
|
128
|
+
|
|
129
|
+
## Calling endpoints
|
|
130
|
+
|
|
131
|
+
Endpoint names use dashes, like `list-items`. The client exposes them as Ruby
|
|
132
|
+
methods with underscores, like `list_items`. You pass arguments as keywords:
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
client.list_items(limit: 10, offset: 20)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The return value is the parsed JSON response. It can be a hash, an array, a
|
|
139
|
+
string, a number, a boolean, or `nil`.
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
client.get_count # => 42
|
|
143
|
+
client.list_items # => [{ "id" => 1 }]
|
|
144
|
+
client.find_user(id: "1") # => { "id" => "1", "name" => "Ada" }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
If you prefer to call an endpoint by its name, use `call`:
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
client.call("list-items", limit: 10)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Calling an endpoint that the package does not define raises `NoMethodError`:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
client.does_not_exist
|
|
157
|
+
# => NoMethodError
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Authentication
|
|
161
|
+
|
|
162
|
+
Some endpoints need a bearer token. Pass it when you build the client and the
|
|
163
|
+
gem adds an `Authorization: Bearer <token>` header to every call:
|
|
164
|
+
|
|
165
|
+
```ruby
|
|
166
|
+
client = WebFunction::Client.from_package_endpoint(
|
|
167
|
+
"https://api.example.com/package",
|
|
168
|
+
bearer_auth: "my-token",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
client.list_orders
|
|
15
172
|
```
|
|
16
173
|
|
|
17
|
-
|
|
174
|
+
The gem does not handle login. How you obtain the token is up to you. To find
|
|
175
|
+
out whether an endpoint needs a token, check its `bearer_auth?` flag:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
endpoint = client.package.endpoint("list-orders")
|
|
179
|
+
endpoint.bearer_auth? # => true
|
|
180
|
+
endpoint.capture_bearer? # => false
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Versioning
|
|
184
|
+
|
|
185
|
+
A versioned package selects its version through the `Api-Version` header. Pass a
|
|
186
|
+
version string when you build the client:
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
client = WebFunction::Client.from_package_endpoint(
|
|
190
|
+
"https://api.example.com/package",
|
|
191
|
+
version: "2024-01-01",
|
|
192
|
+
)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
You can ask a package whether it is versioned and which versions it offers:
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
package = client.package
|
|
199
|
+
package.versioned? # => true
|
|
200
|
+
package.version # => "2024-01-01"
|
|
201
|
+
package.versions # => ["2023-06-01", "2024-01-01"]
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Inspecting a package
|
|
205
|
+
|
|
206
|
+
A package describes itself. You can read its metadata, walk its endpoints, and
|
|
207
|
+
look at the arguments and outputs of each one. This is useful for building docs
|
|
208
|
+
or for checking a call before you make it.
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
package = client.package
|
|
212
|
+
|
|
213
|
+
package.name # => "Example API"
|
|
214
|
+
package.base_url # => "https://api.example.com/"
|
|
215
|
+
package.docs # => "Markdown documentation for the package."
|
|
216
|
+
package.endpoints # => [#<WebFunction::Endpoint ...>, ...]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Look up a single endpoint by name. Underscores and dashes both work:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
endpoint = package.endpoint("find-user")
|
|
223
|
+
# Same as:
|
|
224
|
+
endpoint = package.endpoint(:find_user)
|
|
225
|
+
|
|
226
|
+
endpoint.name # => "find-user"
|
|
227
|
+
endpoint.docs # => "Retrieves user data."
|
|
228
|
+
endpoint.returns # => ["object"]
|
|
229
|
+
endpoint.group # => "Users"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Each endpoint lists the arguments it takes:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
endpoint.arguments
|
|
236
|
+
# => [#<WebFunction::Argument ...>]
|
|
237
|
+
|
|
238
|
+
id = endpoint.argument("id")
|
|
239
|
+
id.name # => "id"
|
|
240
|
+
id.type # => "string"
|
|
241
|
+
id.required? # => true
|
|
242
|
+
id.optional? # => false
|
|
243
|
+
id.choices # => []
|
|
244
|
+
id.docs # => "Identifier of the user."
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
It also lists the attributes it returns when the return type is an object:
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
name = endpoint.attribute("name")
|
|
251
|
+
name.name # => "name"
|
|
252
|
+
name.type # => "string"
|
|
253
|
+
name.nullable? # => false
|
|
254
|
+
name.values # => []
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
You can call an endpoint object directly once it belongs to a client:
|
|
258
|
+
|
|
259
|
+
```ruby
|
|
260
|
+
endpoint = client.package.endpoint("find-user")
|
|
261
|
+
endpoint.call(id: "123")
|
|
262
|
+
# => { "id" => "123", "name" => "Ada" }
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Error handling
|
|
266
|
+
|
|
267
|
+
Every error this gem raises inherits from `WebFunction::Error`. Each error
|
|
268
|
+
carries a `code` and optional `details`.
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
begin
|
|
272
|
+
client.find_user(id: "missing")
|
|
273
|
+
rescue WebFunction::Error => e
|
|
274
|
+
e.code # => "USER_NOT_FOUND"
|
|
275
|
+
e.message # => "No user with that id."
|
|
276
|
+
e.details # => { "id" => "missing" }
|
|
277
|
+
end
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
These are the error classes:
|
|
281
|
+
|
|
282
|
+
| Class | Raised when |
|
|
283
|
+
| --- | --- |
|
|
284
|
+
| `WebFunction::BadRequestError` | The server replied with status `400`. |
|
|
285
|
+
| `WebFunction::UnexpectedStatusCodeError` | The server replied with a status other than `200` or `400`. |
|
|
286
|
+
| `WebFunction::JsonParseError` | The response body was not valid JSON. |
|
|
287
|
+
| `WebFunction::UnresolvedPromiseError` | A pipeline promise was read before it resolved. |
|
|
288
|
+
|
|
289
|
+
When the server returns a `400`, the body is an error triple. A triple is a
|
|
290
|
+
JSON array with three parts: a code, a message, and details. The gem reads the
|
|
291
|
+
triple and fills in the error:
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
["USER_NOT_FOUND", "No user with that id.", { "id": "missing" }]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
```ruby
|
|
298
|
+
rescue WebFunction::BadRequestError => e
|
|
299
|
+
e.code # => "USER_NOT_FOUND"
|
|
300
|
+
e.message # => "No user with that id."
|
|
301
|
+
e.details # => { "id" => "missing" }
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
If the body is not a triple, the gem still raises `BadRequestError` with the
|
|
305
|
+
code `WFN_BAD_REQUEST_ERROR` and puts the raw body in `details`.
|
|
306
|
+
|
|
307
|
+
An endpoint can document the errors it may return. Read them when the endpoint
|
|
308
|
+
uses the `error_triple` flag:
|
|
309
|
+
|
|
310
|
+
```ruby
|
|
311
|
+
endpoint.errors
|
|
312
|
+
# => [#<WebFunction::DocumentedError code="USER_NOT_FOUND" ...>]
|
|
313
|
+
|
|
314
|
+
error = endpoint.error("USER_NOT_FOUND")
|
|
315
|
+
error.code # => "USER_NOT_FOUND"
|
|
316
|
+
error.docs # => "Returned when no user matches the id."
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
The package can document shared errors too:
|
|
320
|
+
|
|
321
|
+
```ruby
|
|
322
|
+
package.errors
|
|
323
|
+
package.error("RATE_LIMITED")
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Pipelining
|
|
327
|
+
|
|
328
|
+
Pipelining sends several calls in one HTTP request. The server runs them in
|
|
329
|
+
order and you can feed the output of one call into the next. This cuts the
|
|
330
|
+
number of round trips.
|
|
331
|
+
|
|
332
|
+
Build a pipelined client and each call returns a `WebFunction::Promise` instead
|
|
333
|
+
of a value. A promise stands in for a result that does not exist yet:
|
|
334
|
+
|
|
335
|
+
```ruby
|
|
336
|
+
client = WebFunction::Client.from_package_endpoint(
|
|
337
|
+
"https://api.example.com/package",
|
|
338
|
+
pipelined: true,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
user = client.find_user(id: "123") # => a Promise
|
|
342
|
+
order = client.create_order(user_id: user["id"]) # uses the first result
|
|
343
|
+
|
|
344
|
+
order.resolve
|
|
345
|
+
# => { "id" => "order-1", "user_id" => "123" }
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Reading `user["id"]` before the call runs does not return a value. It returns a
|
|
349
|
+
path into the future result. The gem sends that path to the server, and the
|
|
350
|
+
server fills it in when it runs the second call. Calling `resolve` runs the
|
|
351
|
+
whole pipeline and returns the value.
|
|
352
|
+
|
|
353
|
+
Once a pipeline runs, every promise from that batch holds its value:
|
|
354
|
+
|
|
355
|
+
```ruby
|
|
356
|
+
user.resolve # runs the pipeline
|
|
357
|
+
order.value # already available, no extra request
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
You can also drive a pipeline by hand with `WebFunction::Pipeline`. Each step is
|
|
361
|
+
a hash with a `url`, `headers`, and `body`:
|
|
362
|
+
|
|
363
|
+
```ruby
|
|
364
|
+
pipeline = WebFunction::Pipeline.new("https://api.example.com/run-pipeline")
|
|
365
|
+
|
|
366
|
+
pipeline.add_step(url: "https://api.example.com/a", headers: {}, body: {})
|
|
367
|
+
pipeline.add_step(url: "https://api.example.com/b", headers: {}, body: {})
|
|
368
|
+
|
|
369
|
+
pipeline.execute(returns: :all)
|
|
370
|
+
# => [{ "a" => 1 }, { "b" => 2 }]
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
The `returns` option controls what comes back:
|
|
374
|
+
|
|
375
|
+
- `:all` returns every step result as an array. This is the default.
|
|
376
|
+
- `:last` returns only the last step result.
|
|
377
|
+
- A JSONPath string returns the value at that path, for example `"$[0].id"`.
|
|
378
|
+
|
|
379
|
+
## Custom HTTP client
|
|
380
|
+
|
|
381
|
+
By default the gem makes requests with [Excon](https://github.com/excon/excon).
|
|
382
|
+
You can swap in any HTTP client by setting `WebFunction::Request.http_client` to
|
|
383
|
+
an object that responds to `call`.
|
|
384
|
+
|
|
385
|
+
The object receives the URL, the headers, and the JSON body. It must return a
|
|
386
|
+
two-element array of the status code and the raw response body:
|
|
387
|
+
|
|
388
|
+
```ruby
|
|
389
|
+
WebFunction::Request.http_client = ->(url, headers, body) do
|
|
390
|
+
response = MyHttp.post(url, headers: headers, body: body)
|
|
391
|
+
[response.status, response.body]
|
|
392
|
+
end
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
This is also handy in tests, where you can return a canned response without
|
|
396
|
+
making a real request:
|
|
397
|
+
|
|
398
|
+
```ruby
|
|
399
|
+
WebFunction::Request.http_client = ->(_url, _headers, _body) do
|
|
400
|
+
[200, JSON.generate({ "id" => "123" })]
|
|
401
|
+
end
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## Low-level requests
|
|
405
|
+
|
|
406
|
+
If you do not need a package, you can call a single endpoint URL directly with
|
|
407
|
+
`WebFunction::Request`:
|
|
408
|
+
|
|
409
|
+
```ruby
|
|
410
|
+
WebFunction::Request.execute(
|
|
411
|
+
"https://api.example.com/find-user",
|
|
412
|
+
bearer_auth: "my-token",
|
|
413
|
+
version: "2024-01-01",
|
|
414
|
+
args: { id: "123" },
|
|
415
|
+
)
|
|
416
|
+
# => { "id" => "123", "name" => "Ada" }
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
The request adds the standard headers, posts the JSON body, and parses the
|
|
420
|
+
response. It raises the same errors described in [Error handling](#error-handling).
|
|
421
|
+
|
|
422
|
+
## Command line tool
|
|
423
|
+
|
|
424
|
+
The gem ships with a `wfn` command. Use it to call an endpoint from the shell.
|
|
425
|
+
Arguments go in a JSON string:
|
|
18
426
|
|
|
19
427
|
```bash
|
|
20
|
-
|
|
428
|
+
wfn call https://api.example.com/find-user '{"id":"123"}'
|
|
21
429
|
```
|
|
22
430
|
|
|
23
|
-
|
|
431
|
+
Pass a bearer token with `--auth` and a version with `--version`:
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
wfn call --auth my-token --version 2024-01-01 \
|
|
435
|
+
https://api.example.com/list-orders '{}'
|
|
436
|
+
```
|
|
24
437
|
|
|
25
|
-
|
|
438
|
+
The command prints the response as formatted JSON. On an error it prints the
|
|
439
|
+
code, the message, and the details, then exits with a non-zero status.
|
|
26
440
|
|
|
27
441
|
## Development
|
|
28
442
|
|
|
29
|
-
After
|
|
443
|
+
After you check out the repo, run `bin/setup` to install dependencies. Then run
|
|
444
|
+
`rake test` to run the tests. Run `bin/console` for a prompt where you can
|
|
445
|
+
experiment with the code.
|
|
30
446
|
|
|
31
|
-
To install
|
|
447
|
+
To install the gem on your machine, run `bundle exec rake install`. To release a
|
|
448
|
+
new version, update the version in `lib/web_function/version.rb`, then run
|
|
449
|
+
`bundle exec rake release`. This creates a git tag, pushes the commits and the
|
|
450
|
+
tag, and pushes the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
32
451
|
|
|
33
452
|
## Contributing
|
|
34
453
|
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at
|
|
454
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
455
|
+
[github.com/robinclart/web_function](https://github.com/robinclart/web_function).
|
|
36
456
|
|
|
37
457
|
## License
|
|
38
458
|
|
|
39
|
-
|
|
459
|
+
This gem is open source under the terms of the
|
|
460
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/exe/wfn
CHANGED
|
@@ -8,10 +8,17 @@ require "json"
|
|
|
8
8
|
# wfn call --auth token endpoint_url key1=value1 [key2=value2 ...]
|
|
9
9
|
|
|
10
10
|
auth_token = nil
|
|
11
|
-
|
|
12
|
-
if
|
|
13
|
-
auth_token = ARGV[
|
|
14
|
-
ARGV.slice!(
|
|
11
|
+
auth_index = ARGV.index("--auth")
|
|
12
|
+
if auth_index
|
|
13
|
+
auth_token = ARGV[auth_index + 1]
|
|
14
|
+
ARGV.slice!(auth_index, 2)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
version = nil
|
|
18
|
+
version_index = ARGV.index("--version")
|
|
19
|
+
if version_index
|
|
20
|
+
version = ARGV[version_index + 1]
|
|
21
|
+
ARGV.slice!(version_index, 2)
|
|
15
22
|
end
|
|
16
23
|
|
|
17
24
|
command = ARGV[0]
|
|
@@ -22,7 +29,7 @@ when "call"
|
|
|
22
29
|
args = JSON.parse(ARGV[2] || "{}")
|
|
23
30
|
|
|
24
31
|
begin
|
|
25
|
-
response = WebFunction::
|
|
32
|
+
response = WebFunction::Request.execute(endpoint_url, bearer_auth: auth_token, version: version, args: args)
|
|
26
33
|
puts JSON.pretty_generate(response)
|
|
27
34
|
rescue WebFunction::Error => e
|
|
28
35
|
puts e
|