hub_kernel-api 0.5.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 005a2ef443ca851aa60b1e07bbf00d20f36ad682a7dcba572fcb2c5847181831
4
- data.tar.gz: 3da76e3b5993936cc999d4641e2d4b70476a8fb7d86451294a7a5f583b85fb0c
3
+ metadata.gz: 012cd9631dd8925bcd3d6982acc076ee8ade6a159dbca527d3618ba4ff80eec4
4
+ data.tar.gz: 98850fb2e56aca0a182d1f70adc2deedb440e9b54f0f188e321a2738034d8991
5
5
  SHA512:
6
- metadata.gz: 36883d22bb606c36eca8c7e80620d1a8c07105254f41152a87e28c4317f91ff23ec58f5a6aa17971d106577695f25f2e8c5e3aa8b329108303a0ca8f341326fb
7
- data.tar.gz: 78348ad9a3c18cffff53beadc24f99a15a5d0b4524a592da883e807966648bef9f550945bd059cacc60e03d60084bed3c0d8a8ead26c7d702baaca0c43eabaeb
6
+ metadata.gz: b2e7fc3101f127f70f515be313c0532efd5a64bce8f568dc693fa2e7e3a962dad5703ea5a295e3020cc56b644fc283854a140ac24d7f588d891227b30934bf70
7
+ data.tar.gz: 67b21cabf1dd75ad74c7c97a3d908432a7c508c5fd39b13a3108a63ede102b8864fc4dde26c47f6da666dbdd3234351e764a3d1d0f6431d4275fc94f7dbb12e9
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # hub_kernel-api
2
2
 
3
3
  Serves a hub_kernel hub's exposed methods as a JSON API. The host lists the hubs it
4
- serves, and every call goes through the host's own sign-in, then hub_kernel's permission
5
- check and account scope.
4
+ serves, and every call goes through the host's own sign-in, then the permission check and
5
+ account scope that hub_kernel-interface holds. It depends on hub_kernel-interface alone, not
6
+ on hub_kernel.
6
7
 
7
8
  ## Usage
8
9
 
@@ -26,8 +27,9 @@ exposes no methods, when two served hubs answer at the same address, or when a s
26
27
  hub's exposed list has a problem, naming each. Inside `to_prepare` it runs again after
27
28
  every code reload.
28
29
 
29
- The base controller's own sign-in runs before every call. hub_kernel's permission check
30
- and account scope must also be set, as hub_kernel's readme describes. Mount the engine:
30
+ The base controller's own sign-in runs before every call. The permission check and account
31
+ scope must also be set, `HubKernel::Authz.check` and `HubKernel::Context.scope`, as
32
+ hub_kernel-interface's readme describes. Mount the engine:
31
33
 
32
34
  ```ruby
33
35
  mount HubKernel::Api::Engine => "/api/v1/hubs"
data/Rakefile CHANGED
@@ -4,3 +4,5 @@ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
4
  load "rails/tasks/engine.rake"
5
5
 
6
6
  require "bundler/gem_tasks"
7
+
8
+ require "the_local/rake"
@@ -1,5 +1,5 @@
1
1
  module HubKernel
2
2
  module Api
3
- VERSION = "0.5.0"
3
+ VERSION = "0.7.0"
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- require "hub_kernel"
1
+ require "hub_kernel-interface"
2
2
  require "hub_kernel/api/version"
3
3
  require "hub_kernel/api/engine"
4
4
 
@@ -0,0 +1,110 @@
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-interface'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 the permission check and
15
+ account scope that hub_kernel-interface holds. Use this local when writing a front end,
16
+ mobile app, service or request test that calls those methods, or when working out why a
17
+ call answered as it did. Adding the gem, choosing the served hubs and mounting the engine
18
+ belong to the install 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, stop and use the install local.
36
+
37
+ 2. Find the hub's address. A hub answers at its module name underscored, so `Supplies`
38
+ answers at `supplies`, unless the host listed it under a name of its own, such as
39
+ `{ "money" => Billing::Ledger }`, in which case it answers only at `money`. Read the
40
+ host's served hubs list in its initializer to find it.
41
+
42
+ 3. Authenticate the request the way the host's sign-in requires, such as a session
43
+ cookie or a bearer token. Ask the developer which one the client uses. A request the
44
+ host's sign-in refuses is answered by the host, with the host's own status, and
45
+ reaches no hub.
46
+
47
+ 4. List what the caller may call:
48
+
49
+ ```
50
+ GET /api/v1/hubs/supplies
51
+ ```
52
+
53
+ ```json
54
+ [{ "name": "price_of", "takes": ["item"], "verb": "GET" },
55
+ { "name": "reorder", "takes": ["item", "quantity"], "verb": "POST" }]
56
+ ```
57
+
58
+ The list holds only the methods this caller is permitted on this account. Use `verb`
59
+ to choose GET or POST, and `takes` for the value names the method accepts.
60
+
61
+ 5. Call a read with GET, sending its values as query parameters:
62
+
63
+ ```
64
+ GET /api/v1/hubs/supplies/price_of?item=42
65
+ ```
66
+
67
+ Query values arrive as strings.
68
+
69
+ 6. Call a write with POST, sending its values as a JSON body with
70
+ `Content-Type: application/json`, keyed directly by value name with no wrapping key:
71
+
72
+ ```
73
+ POST /api/v1/hubs/supplies/reorder
74
+ Content-Type: application/json
75
+
76
+ { "item": 42, "quantity": 3 }
77
+ ```
78
+
79
+ Query parameters on a POST are sent to the method as well. Do not send a value whose
80
+ name is not in `takes`.
81
+
82
+ 7. Read the response by status:
83
+
84
+ | Case | Status | Body |
85
+ | --- | --- | --- |
86
+ | The method answers | 200 | `{"answer": <return value>}` |
87
+ | 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"}` |
88
+ | The hub refuses the call, or a required value is missing | 422 | `{"error": "<reason>"}` |
89
+ | A permitted call sends a value the method does not take | 422 | `{"error": "<method> does not take <values>"}` |
90
+ | A record the call names does not exist | 404 | `{"error": "No <record> has the id <id>"}` |
91
+
92
+ Show the `error` text of a 422 to the user, since it is the hub's reason. Treat
93
+ `Not found` as a method that does not exist for this caller.
94
+
95
+ 8. For a request test in the host, sign in as a person with and without the permission,
96
+ and assert the 200 answer for one and the `Not found` 404 for the other.
97
+
98
+ ## Conventions
99
+
100
+ - Never send GET to a write or POST to a read; the wrong verb is answered as not found,
101
+ never as a method error.
102
+ - A forbidden method and a missing one both answer `Not found`, so a client cannot tell
103
+ them apart, and must not try.
104
+ - The `answer` is the method's return value as JSON; nothing else is added to it.
105
+ - The account a call is made for comes from the host's sign-in, never from a value in the
106
+ request.
107
+ - Only the methods a hub exposes are reachable; adding a method to the API means exposing
108
+ it on the hub, not adding a route.
109
+ - Installing the gem, configuring it and choosing the served hubs are out of scope here;
110
+ they belong to the install local.
@@ -0,0 +1,66 @@
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-interface'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
+ It depends on hub_kernel-interface alone, not on hub_kernel. hub_kernel-interface
19
+ holds the permission check and the account scope, and the host sets both.
20
+
21
+ Reach for it when a hub's exposed methods need to be called over HTTP, by a mobile
22
+ app, another service or a front end, without writing a controller per method. Each
23
+ call runs the host's own sign-in first, then hub_kernel-interface's permission check
24
+ and account scope, so the API never shows a caller more than the app itself would.
25
+
26
+ ## Interface
27
+
28
+ This local declares no commands. The surface is split between the other two locals:
29
+
30
+ - **hub_kernel-api-install** owns adding the gem to a host, the configuration that
31
+ names the base controller, the person and account methods and the served hubs, the
32
+ startup check that rejects a hub that cannot be served, and mounting the engine.
33
+ - **hub_kernel-api-develop** owns the HTTP endpoints a client calls: the listing at a
34
+ hub's address and the call to one exposed method, with their verbs, request values,
35
+ responses and error statuses.
36
+
37
+ ## How to use it
38
+
39
+ - To put the API into a Rails app, or to serve another hub from one that has it, use
40
+ the install local.
41
+ - To write a client against the API, or to work out why a call answered as it did,
42
+ use the develop local.
43
+
44
+ ## Conventions
45
+
46
+ - **Hub** — a module whose methods are declared as exposed through
47
+ hub_kernel-interface. Only exposed methods are reachable; nothing else on the hub is.
48
+ - **Served hub** — a hub the host has listed for the API. A hub that is not served is
49
+ answered as not found, as if it did not exist.
50
+ - **Address** — the name a served hub answers at. By default it is the hub's module
51
+ name underscored, so `Supplies` answers at `supplies`. The host may give a hub a
52
+ different address, and the permission check still asks about the hub by its own
53
+ name, such as `ledger:record_spend`.
54
+ - **Read and write** — each exposed method is one or the other. A read answers GET
55
+ and a write answers POST, and the wrong verb is answered as not found.
56
+ - **Takes** — the values an exposed method is listed with. A permitted call that
57
+ sends a value outside that list is refused.
58
+ - **Person and account** — who is calling and which account the call is made for,
59
+ both supplied by the host's base controller after its own sign-in. Every call and
60
+ every listing is scoped to them.
61
+ - **Answer** — a successful call returns the method's return value under the
62
+ `answer` key.
63
+ - **Not found and refused** — a call the permission check denies is answered as not
64
+ found, so a caller cannot tell a forbidden method from a missing one. A call the hub
65
+ itself refuses, or one missing a required value, is answered as unprocessable with
66
+ the reason.
@@ -0,0 +1,109 @@
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-interface'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
19
+ hub_kernel-interface with it, and not hub_kernel.
20
+ - `HubKernel::Api.base_controller=` — the name, as a String, of the host controller the
21
+ API's controllers inherit from; defaults to `"ActionController::API"`.
22
+ - `HubKernel::Api.person_method=` — the name, as a Symbol, of the method on the base
23
+ controller that returns the person a call is made for; no default.
24
+ - `HubKernel::Api.account_method=` — the name, as a Symbol, of the method on the base
25
+ controller that returns the account a call is made for; no default.
26
+ - `HubKernel::Api.hubs=` — the Array of hubs the API serves, each a hub module or a
27
+ one-pair Hash of address to hub module; defaults to empty.
28
+ - `HubKernel::Api.check!` — checks the served hubs and raises if any cannot be served.
29
+ - `HubKernel::Api::UnservableHubError` — the error `check!` raises, its message naming
30
+ every problem on its own line.
31
+ - `mount HubKernel::Api::Engine` — the routes line that puts the API at a path in the host.
32
+
33
+ ## How to use it
34
+
35
+ 1. Add the gem to the host's `Gemfile` and run `bundle install`:
36
+
37
+ ```ruby
38
+ gem "hub_kernel-api"
39
+ ```
40
+
41
+ 2. Confirm the permission check and account scope that hub_kernel-interface holds are
42
+ already set in the host: `HubKernel::Authz.check` and `HubKernel::Context.scope`.
43
+ Every call is checked and scoped by them. If the host has a hub_kernel-interface
44
+ install local, use it for this. Otherwise stop and ask the developer how they are
45
+ set, and do not set them from guesswork.
46
+
47
+ 3. Ask the developer which controller the API inherits from. It must:
48
+ - run the host's sign-in before every action, as a `before_action` that refuses an
49
+ unsigned caller;
50
+ - define the method that returns the calling person;
51
+ - define the method that returns the account the call is made for.
52
+
53
+ The methods may be private. Offer two options: an existing API base controller that
54
+ already does all three, or a new one under `app/controllers/` written for this API.
55
+ Do not leave the default `ActionController::API`: it has no sign-in and no person or
56
+ account method, so every call would fail.
57
+
58
+ 4. Ask the developer which hubs to serve and at what address each answers. A hub module
59
+ answers at its module name underscored, so `Supplies` answers at `supplies`. To use a
60
+ different address, the hub is listed as a one-pair Hash, `{ "money" => Billing::Ledger }`.
61
+ Every listed hub must expose methods, and no two may share an address.
62
+
63
+ 5. Create `config/initializers/hub_kernel_api.rb` with the answers from steps 3 and 4:
64
+
65
+ ```ruby
66
+ HubKernel::Api.base_controller = "Api::HubBaseController"
67
+ HubKernel::Api.person_method = :current_person
68
+ HubKernel::Api.account_method = :current_account
69
+
70
+ Rails.application.config.to_prepare do
71
+ HubKernel::Api.hubs = [ Supplies, { "money" => Billing::Ledger } ]
72
+ HubKernel::Api.check!
73
+ end
74
+ ```
75
+
76
+ - `base_controller`, `person_method` and `account_method` go at the top of the file,
77
+ outside `to_prepare`. The base controller name is read once, when the API's
78
+ controllers load, so it must be set before then.
79
+ - `hubs` and `check!` go inside `to_prepare`, so the hub constants resolve after each
80
+ code reload and the check runs again after each one.
81
+
82
+ 6. Ask the developer the path to mount the API at, then add the mount to
83
+ `config/routes.rb`:
84
+
85
+ ```ruby
86
+ mount HubKernel::Api::Engine => "/api/v1/hubs"
87
+ ```
88
+
89
+ 7. Boot the app, for example with `bin/rails runner "puts :ok"`. A
90
+ `HubKernel::Api::UnservableHubError` at boot names each problem:
91
+ - `<Hub> exposes no methods to serve` — the entry is not a hub with exposed methods;
92
+ remove it, or expose methods on it.
93
+ - `<Hub> and <Hub> both answer at <address>` — give one of them its own address with
94
+ a one-pair Hash.
95
+ - Any other line is a problem the hub reports with its own list of exposed methods;
96
+ fix it in the hub.
97
+
98
+ ## Conventions
99
+
100
+ - Run `bin/rails routes` after mounting and confirm the engine appears at the chosen path.
101
+ - To serve another hub later, add it to the `hubs` list inside `to_prepare` and boot
102
+ again so `check!` runs.
103
+ - An edit to the initializer takes effect only after the server restarts.
104
+ - Keep `HubKernel::Api.check!` in the initializer; without it a hub that cannot be served
105
+ is found only when a client calls it.
106
+ - Setting the permission check and account scope is out of scope here; it belongs to
107
+ hub_kernel-interface.
108
+ - Calling the API, its responses and its error statuses are out of scope here; they
109
+ 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-interface'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.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider
@@ -24,19 +24,19 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: 8.1.3
26
26
  - !ruby/object:Gem::Dependency
27
- name: hub_kernel
27
+ name: hub_kernel-interface
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.18'
32
+ version: '0.3'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.18'
39
+ version: '0.3'
40
40
  description: 'hub_kernel-api gives any hub built on hub_kernel a JSON API: the host
41
41
  lists the hubs it serves, and every call goes through the host''s sign-in, permission
42
42
  check and account scope.'
@@ -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