hub_kernel-api 0.5.0 → 0.6.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/Rakefile +2 -0
- data/lib/hub_kernel/api/version.rb +1 -1
- data/the_local/agents/hub_kernel-api-develop.md +111 -0
- data/the_local/agents/hub_kernel-api-info.md +63 -0
- data/the_local/agents/hub_kernel-api-install.md +106 -0
- data/the_local/interface.yml +25 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 16098ba0ceb84acb8536551867732dae646869b478d18299bb85a6839d1db8e1
|
|
4
|
+
data.tar.gz: 5b5b3d49bd804284796e8c7702b861b704c6e6ac77dba9a8e90b73f216845d52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 816027b58264d0c192482819bd043cf28f14c3ec65c91043953c7fba75abdf21725c09db3809f65f506cdab7e89b04a556d7a225cce99da925e1c4b4726fbffc
|
|
7
|
+
data.tar.gz: 2befb90df535ea4e2df15e8d229b058d46339bf730937dabb3e4511bc890abc0a1d2a1f945b6b38b15258453d7ea9c8ef57212685ff0a7f7e8e32038de40bfbb
|
data/Rakefile
CHANGED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hub_kernel-api-develop
|
|
3
|
+
description: Use PROACTIVELY for calling a served hub over HTTP — listing the methods a caller may call at a hub's address, calling a read with GET, calling a write with POST, sending its values, and reading its answer or error status — MUST BE USED instead of hand-writing a controller or endpoint per hub method, or guessing at the API's responses.
|
|
4
|
+
tools: Read, Write, Edit, Grep
|
|
5
|
+
scope: hub JSON API — serving a hub_kernel hub's exposed methods as a JSON API in a host Rails app, each call behind the host's own sign-in and hub_kernel's permission check and account scope
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This local writes client code against the three endpoints below and follows the steps in
|
|
9
|
+
order. Where a step names a decision, it asks the developer and does not pick.
|
|
10
|
+
|
|
11
|
+
## What hub_kernel-api is
|
|
12
|
+
|
|
13
|
+
A Rails engine that answers HTTP calls to the exposed methods of the hubs a host serves,
|
|
14
|
+
each call made after the host's sign-in and checked and scoped by hub_kernel's permission
|
|
15
|
+
check and account scope. Use this local when writing a front end, mobile app, service or
|
|
16
|
+
request test that calls those methods, or when working out why a call answered as it did.
|
|
17
|
+
Adding the gem, choosing the served hubs and mounting the engine belong to the install
|
|
18
|
+
local.
|
|
19
|
+
|
|
20
|
+
## Interface
|
|
21
|
+
|
|
22
|
+
- `GET /<hub>` — lists the methods the signed-in caller may call on the hub at that
|
|
23
|
+
address, for the caller's account, each as `{ "name", "takes", "verb" }`.
|
|
24
|
+
- `GET /<hub>/<method>` — calls an exposed read with the values sent in the query string
|
|
25
|
+
and answers `{ "answer": <return value> }`.
|
|
26
|
+
- `POST /<hub>/<method>` — calls an exposed write with the values sent in the request body
|
|
27
|
+
or query string and answers `{ "answer": <return value> }`.
|
|
28
|
+
|
|
29
|
+
Every path is relative to the path the host mounted the engine at, such as
|
|
30
|
+
`/api/v1/hubs`.
|
|
31
|
+
|
|
32
|
+
## How to use it
|
|
33
|
+
|
|
34
|
+
1. Find the path the host mounted the API at in its `config/routes.rb`. Every URL
|
|
35
|
+
below starts with it. If the API is not mounted,
|
|
36
|
+
stop and use the install local.
|
|
37
|
+
|
|
38
|
+
2. Find the hub's address. A hub answers at its module name underscored, so `Supplies`
|
|
39
|
+
answers at `supplies`, unless the host listed it under a name of its own, such as
|
|
40
|
+
`{ "money" => Billing::Ledger }`, in which case it answers only at `money`. Read the
|
|
41
|
+
host's served hubs list in its initializer to find it.
|
|
42
|
+
|
|
43
|
+
3. Authenticate the request the way the host's sign-in requires, such as a session
|
|
44
|
+
cookie or a bearer token. Ask the developer which one the client uses. A request the
|
|
45
|
+
host's sign-in refuses is answered by the host, with the host's own status, and
|
|
46
|
+
reaches no hub.
|
|
47
|
+
|
|
48
|
+
4. List what the caller may call:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
GET /api/v1/hubs/supplies
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
[{ "name": "price_of", "takes": ["item"], "verb": "GET" },
|
|
56
|
+
{ "name": "reorder", "takes": ["item", "quantity"], "verb": "POST" }]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The list holds only the methods this caller is permitted on this account. Use `verb`
|
|
60
|
+
to choose GET or POST, and `takes` for the value names the method accepts.
|
|
61
|
+
|
|
62
|
+
5. Call a read with GET, sending its values as query parameters:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
GET /api/v1/hubs/supplies/price_of?item=42
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Query values arrive as strings.
|
|
69
|
+
|
|
70
|
+
6. Call a write with POST, sending its values as a JSON body with
|
|
71
|
+
`Content-Type: application/json`, keyed directly by value name with no wrapping key:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
POST /api/v1/hubs/supplies/reorder
|
|
75
|
+
Content-Type: application/json
|
|
76
|
+
|
|
77
|
+
{ "item": 42, "quantity": 3 }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Query parameters on a POST are sent to the method as well. Do not send a value whose
|
|
81
|
+
name is not in `takes`.
|
|
82
|
+
|
|
83
|
+
7. Read the response by status:
|
|
84
|
+
|
|
85
|
+
| Case | Status | Body |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| The method answers | 200 | `{"answer": <return value>}` |
|
|
88
|
+
| The hub is not served, the method is not exposed, the verb is wrong, or the permission check refuses the caller | 404 | `{"error": "Not found"}` |
|
|
89
|
+
| The hub refuses the call, or a required value is missing | 422 | `{"error": "<reason>"}` |
|
|
90
|
+
| A permitted call sends a value the method does not take | 422 | `{"error": "<method> does not take <values>"}` |
|
|
91
|
+
| A record the call names does not exist | 404 | `{"error": "No <record> has the id <id>"}` |
|
|
92
|
+
|
|
93
|
+
Show the `error` text of a 422 to the user, since it is the hub's reason. Treat
|
|
94
|
+
`Not found` as a method that does not exist for this caller.
|
|
95
|
+
|
|
96
|
+
8. For a request test in the host, sign in as a person with and without the permission,
|
|
97
|
+
and assert the 200 answer for one and the `Not found` 404 for the other.
|
|
98
|
+
|
|
99
|
+
## Conventions
|
|
100
|
+
|
|
101
|
+
- Never send GET to a write or POST to a read; the wrong verb is answered as not found,
|
|
102
|
+
never as a method error.
|
|
103
|
+
- A forbidden method and a missing one both answer `Not found`, so a client cannot tell
|
|
104
|
+
them apart, and must not try.
|
|
105
|
+
- The `answer` is the method's return value as JSON; nothing else is added to it.
|
|
106
|
+
- The account a call is made for comes from the host's sign-in, never from a value in the
|
|
107
|
+
request.
|
|
108
|
+
- Only the methods a hub exposes are reachable; adding a method to the API means exposing
|
|
109
|
+
it on the hub in hub_kernel, not adding a route.
|
|
110
|
+
- Installing the gem, configuring it and choosing the served hubs are out of scope here;
|
|
111
|
+
they belong to the install local.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hub_kernel-api-info
|
|
3
|
+
description: Use to learn what hub_kernel-api offers — serving a hub's exposed methods as a JSON API, the served hubs and their addresses, reads and writes, and how sign-in, permission and account scope apply to each call.
|
|
4
|
+
tools: Read
|
|
5
|
+
scope: hub JSON API — serving a hub_kernel hub's exposed methods as a JSON API in a host Rails app, each call behind the host's own sign-in and hub_kernel's permission check and account scope
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This local explains hub_kernel-api and makes no changes.
|
|
9
|
+
|
|
10
|
+
## What hub_kernel-api is
|
|
11
|
+
|
|
12
|
+
hub_kernel-api is a Rails engine that serves the exposed methods of hub_kernel hubs
|
|
13
|
+
as a JSON API inside a host Rails app. The host lists which hubs it serves, and the
|
|
14
|
+
gem answers HTTP calls to their exposed methods and to a listing of them. It adds no
|
|
15
|
+
business logic of its own: every answer is the return value of a method the hub
|
|
16
|
+
already exposes.
|
|
17
|
+
|
|
18
|
+
Reach for it when a hub's exposed methods need to be called over HTTP, by a mobile
|
|
19
|
+
app, another service or a front end, without writing a controller per method. Each
|
|
20
|
+
call runs the host's own sign-in first, then hub_kernel's permission check and
|
|
21
|
+
account scope, so the API never shows a caller more than the app itself would.
|
|
22
|
+
|
|
23
|
+
## Interface
|
|
24
|
+
|
|
25
|
+
This local declares no commands. The surface is split between the other two locals:
|
|
26
|
+
|
|
27
|
+
- **hub_kernel-api-install** owns adding the gem to a host, the configuration that
|
|
28
|
+
names the base controller, the person and account methods and the served hubs, the
|
|
29
|
+
startup check that rejects a hub that cannot be served, and mounting the engine.
|
|
30
|
+
- **hub_kernel-api-develop** owns the HTTP endpoints a client calls: the listing at a
|
|
31
|
+
hub's address and the call to one exposed method, with their verbs, request values,
|
|
32
|
+
responses and error statuses.
|
|
33
|
+
|
|
34
|
+
## How to use it
|
|
35
|
+
|
|
36
|
+
- To put the API into a Rails app, or to serve another hub from one that has it, use
|
|
37
|
+
the install local.
|
|
38
|
+
- To write a client against the API, or to work out why a call answered as it did,
|
|
39
|
+
use the develop local.
|
|
40
|
+
|
|
41
|
+
## Conventions
|
|
42
|
+
|
|
43
|
+
- **Hub** — a hub_kernel module whose methods are declared as exposed. Only exposed
|
|
44
|
+
methods are reachable; nothing else on the hub is.
|
|
45
|
+
- **Served hub** — a hub the host has listed for the API. A hub that is not served is
|
|
46
|
+
answered as not found, as if it did not exist.
|
|
47
|
+
- **Address** — the name a served hub answers at. By default it is the hub's module
|
|
48
|
+
name underscored, so `Supplies` answers at `supplies`. The host may give a hub a
|
|
49
|
+
different address, and the permission check still asks about the hub by its own
|
|
50
|
+
name, such as `ledger:record_spend`.
|
|
51
|
+
- **Read and write** — each exposed method is one or the other. A read answers GET
|
|
52
|
+
and a write answers POST, and the wrong verb is answered as not found.
|
|
53
|
+
- **Takes** — the values an exposed method is listed with. A permitted call that
|
|
54
|
+
sends a value outside that list is refused.
|
|
55
|
+
- **Person and account** — who is calling and which account the call is made for,
|
|
56
|
+
both supplied by the host's base controller after its own sign-in. Every call and
|
|
57
|
+
every listing is scoped to them.
|
|
58
|
+
- **Answer** — a successful call returns the method's return value under the
|
|
59
|
+
`answer` key.
|
|
60
|
+
- **Not found and refused** — a call the permission check denies is answered as not
|
|
61
|
+
found, so a caller cannot tell a forbidden method from a missing one. A call the hub
|
|
62
|
+
itself refuses, or one missing a required value, is answered as unprocessable with
|
|
63
|
+
the reason.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hub_kernel-api-install
|
|
3
|
+
description: Use to hook hub_kernel-api into a project — adding the gem, naming the base controller and its person and account methods, listing the served hubs, running the startup check, and mounting the engine.
|
|
4
|
+
tools: Bash, Read, Edit
|
|
5
|
+
scope: hub JSON API — serving a hub_kernel hub's exposed methods as a JSON API in a host Rails app, each call behind the host's own sign-in and hub_kernel's permission check and account scope
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This local follows the steps below exactly and invents none. Where a step names a
|
|
9
|
+
decision, it asks the developer and does not pick.
|
|
10
|
+
|
|
11
|
+
## What hub_kernel-api is
|
|
12
|
+
|
|
13
|
+
A Rails engine that serves the exposed methods of hub_kernel hubs as a JSON API; hook it
|
|
14
|
+
in when a Rails app needs its hubs callable over HTTP.
|
|
15
|
+
|
|
16
|
+
## Interface
|
|
17
|
+
|
|
18
|
+
- `gem "hub_kernel-api"` — the Gemfile line that adds the gem; it brings hub_kernel with it.
|
|
19
|
+
- `HubKernel::Api.base_controller=` — the name, as a String, of the host controller the
|
|
20
|
+
API's controllers inherit from; defaults to `"ActionController::API"`.
|
|
21
|
+
- `HubKernel::Api.person_method=` — the name, as a Symbol, of the method on the base
|
|
22
|
+
controller that returns the person a call is made for; no default.
|
|
23
|
+
- `HubKernel::Api.account_method=` — the name, as a Symbol, of the method on the base
|
|
24
|
+
controller that returns the account a call is made for; no default.
|
|
25
|
+
- `HubKernel::Api.hubs=` — the Array of hubs the API serves, each a hub module or a
|
|
26
|
+
one-pair Hash of address to hub module; defaults to empty.
|
|
27
|
+
- `HubKernel::Api.check!` — checks the served hubs and raises if any cannot be served.
|
|
28
|
+
- `HubKernel::Api::UnservableHubError` — the error `check!` raises, its message naming
|
|
29
|
+
every problem on its own line.
|
|
30
|
+
- `mount HubKernel::Api::Engine` — the routes line that puts the API at a path in the host.
|
|
31
|
+
|
|
32
|
+
## How to use it
|
|
33
|
+
|
|
34
|
+
1. Add the gem to the host's `Gemfile` and run `bundle install`:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
gem "hub_kernel-api"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. Confirm hub_kernel's permission check and account scope are already configured in
|
|
41
|
+
the host. Every call is checked and scoped by them. If the host has a hub_kernel
|
|
42
|
+
install local, use it for this; otherwise stop and ask the developer how they are
|
|
43
|
+
set, and do not configure them from guesswork.
|
|
44
|
+
|
|
45
|
+
3. Ask the developer which controller the API inherits from. It must:
|
|
46
|
+
- run the host's sign-in before every action, as a `before_action` that refuses an
|
|
47
|
+
unsigned caller;
|
|
48
|
+
- define the method that returns the calling person;
|
|
49
|
+
- define the method that returns the account the call is made for.
|
|
50
|
+
|
|
51
|
+
The methods may be private. Offer two options: an existing API base controller that
|
|
52
|
+
already does all three, or a new one under `app/controllers/` written for this API.
|
|
53
|
+
Do not leave the default `ActionController::API`: it has no sign-in and no person or
|
|
54
|
+
account method, so every call would fail.
|
|
55
|
+
|
|
56
|
+
4. Ask the developer which hubs to serve and at what address each answers. A hub module
|
|
57
|
+
answers at its module name underscored, so `Supplies` answers at `supplies`. To use a
|
|
58
|
+
different address, the hub is listed as a one-pair Hash, `{ "money" => Billing::Ledger }`.
|
|
59
|
+
Every listed hub must be a hub_kernel hub that exposes methods, and no two may share
|
|
60
|
+
an address.
|
|
61
|
+
|
|
62
|
+
5. Create `config/initializers/hub_kernel_api.rb` with the answers from steps 3 and 4:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
HubKernel::Api.base_controller = "Api::HubBaseController"
|
|
66
|
+
HubKernel::Api.person_method = :current_person
|
|
67
|
+
HubKernel::Api.account_method = :current_account
|
|
68
|
+
|
|
69
|
+
Rails.application.config.to_prepare do
|
|
70
|
+
HubKernel::Api.hubs = [ Supplies, { "money" => Billing::Ledger } ]
|
|
71
|
+
HubKernel::Api.check!
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `base_controller`, `person_method` and `account_method` go at the top of the file,
|
|
76
|
+
outside `to_prepare`. The base controller name is read once, when the API's
|
|
77
|
+
controllers load, so it must be set before then.
|
|
78
|
+
- `hubs` and `check!` go inside `to_prepare`, so the hub constants resolve after each
|
|
79
|
+
code reload and the check runs again after each one.
|
|
80
|
+
|
|
81
|
+
6. Ask the developer the path to mount the API at, then add the mount to
|
|
82
|
+
`config/routes.rb`:
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
mount HubKernel::Api::Engine => "/api/v1/hubs"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
7. Boot the app, for example with `bin/rails runner "puts :ok"`. A
|
|
89
|
+
`HubKernel::Api::UnservableHubError` at boot names each problem:
|
|
90
|
+
- `<Hub> exposes no methods to serve` — the entry is not a hub with exposed methods;
|
|
91
|
+
remove it, or expose methods on it in hub_kernel.
|
|
92
|
+
- `<Hub> and <Hub> both answer at <address>` — give one of them its own address with
|
|
93
|
+
a one-pair Hash.
|
|
94
|
+
- Any other line is a problem with that hub's list of exposed methods, reported by
|
|
95
|
+
hub_kernel; fix it in the hub.
|
|
96
|
+
|
|
97
|
+
## Conventions
|
|
98
|
+
|
|
99
|
+
- Run `bin/rails routes` after mounting and confirm the engine appears at the chosen path.
|
|
100
|
+
- To serve another hub later, add it to the `hubs` list inside `to_prepare` and boot
|
|
101
|
+
again so `check!` runs.
|
|
102
|
+
- An edit to the initializer takes effect only after the server restarts.
|
|
103
|
+
- Keep `HubKernel::Api.check!` in the initializer; without it a hub that cannot be served
|
|
104
|
+
is found only when a client calls it.
|
|
105
|
+
- Calling the API, its responses and its error statuses are out of scope here; they
|
|
106
|
+
belong to the develop local.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
scope: hub JSON API — serving a hub_kernel hub's exposed methods as a JSON API in a host Rails app, each call behind the host's own sign-in and hub_kernel's permission check and account scope
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
- gem "hub_kernel-api"
|
|
5
|
+
- HubKernel::Api.base_controller=
|
|
6
|
+
- HubKernel::Api.person_method=
|
|
7
|
+
- HubKernel::Api.account_method=
|
|
8
|
+
- HubKernel::Api.hubs=
|
|
9
|
+
- HubKernel::Api.check!
|
|
10
|
+
- HubKernel::Api::UnservableHubError
|
|
11
|
+
- mount HubKernel::Api::Engine
|
|
12
|
+
|
|
13
|
+
develop:
|
|
14
|
+
- GET /<hub>
|
|
15
|
+
- GET /<hub>/<method>
|
|
16
|
+
- POST /<hub>/<method>
|
|
17
|
+
|
|
18
|
+
sources:
|
|
19
|
+
- lib/hub_kernel/api.rb
|
|
20
|
+
- lib/hub_kernel/api/engine.rb
|
|
21
|
+
- config/routes.rb
|
|
22
|
+
- app/controllers/hub_kernel/api/hub_controller.rb
|
|
23
|
+
- app/controllers/hub_kernel/api/hubs_controller.rb
|
|
24
|
+
- app/controllers/hub_kernel/api/hub_calls_controller.rb
|
|
25
|
+
- README.md
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hub_kernel-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- tylercschneider
|
|
@@ -57,6 +57,10 @@ files:
|
|
|
57
57
|
- lib/hub_kernel/api.rb
|
|
58
58
|
- lib/hub_kernel/api/engine.rb
|
|
59
59
|
- lib/hub_kernel/api/version.rb
|
|
60
|
+
- the_local/agents/hub_kernel-api-develop.md
|
|
61
|
+
- the_local/agents/hub_kernel-api-info.md
|
|
62
|
+
- the_local/agents/hub_kernel-api-install.md
|
|
63
|
+
- the_local/interface.yml
|
|
60
64
|
homepage: https://github.com/DYB-Development/hub_kernel-api
|
|
61
65
|
licenses:
|
|
62
66
|
- MIT
|