hub_kernel-api 0.9.0 → 0.10.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.
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
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, listing the majors served and marking the ones deprecated or retired, running the startup check, and mounting the engine.
4
4
  tools: Bash, Read, Edit
5
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
6
  ---
@@ -20,14 +20,31 @@ in when a Rails app needs its hubs callable over HTTP.
20
20
  - `HubKernel::Api.base_controller=` — the name, as a String, of the host controller the
21
21
  API's controllers inherit from; defaults to `"ActionController::API"`.
22
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.
23
+ controller that returns the person a call is made for; when unset, the API uses
24
+ `HubKernel::Interface.person_method`.
24
25
  - `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
+ controller that returns the account a call is made for; when unset, the API uses
27
+ `HubKernel::Interface.account_method`.
26
28
  - `HubKernel::Api.hubs=` — the Array of hubs the API serves, each a hub module or a
27
29
  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.
30
+ - `HubKernel::Api.versions=` — the Array of majors the API serves, each a
31
+ `HubKernel::Api::MajorVersion`; defaults to empty, which turns versioning off.
32
+ - `HubKernel::Api::MajorVersion` — one listed major, built as
33
+ `HubKernel::Api::MajorVersion.new(version: "1.4.0")`; its major is the first part of
34
+ the version. `deprecated: true` marks a major the host still serves but plans to stop
35
+ serving, `deprecated_on:` gives a deprecated major the `Date` it was deprecated, and
36
+ `sunset:` gives it the `Date` it stops being served. `retired: true` marks a major the
37
+ host keeps listed but no longer serves.
38
+ - `HubKernel::Api.check!` — checks the served hubs and the listed majors, and raises if
39
+ any hub cannot be served or the majors hold a mistake.
29
40
  - `HubKernel::Api::UnservableHubError` — the error `check!` raises, its message naming
30
41
  every problem on its own line.
42
+ - `HubKernel::Api::UnservedMajorError` — the error the API raises when a call or a listing
43
+ names a major the host does not list, whether or not the hub it names is served; the API
44
+ answers that call with status 406 and the error's message, and the host does not rescue it.
45
+ - `HubKernel::Api::RetiredMajorError` — the error the API raises when a call or a listing
46
+ names a retired major, whether or not the hub it names is served; the API answers that
47
+ call with status 410 and the error's message, and the host does not rescue it.
31
48
  - `mount HubKernel::Api::Engine` — the routes line that puts the API at a path in the host.
32
49
 
33
50
  ## How to use it
@@ -55,17 +72,58 @@ in when a Rails app needs its hubs callable over HTTP.
55
72
  Do not leave the default `ActionController::API`: it has no sign-in and no person or
56
73
  account method, so every call would fail.
57
74
 
58
- 4. Ask the developer which hubs to serve and at what address each answers. A hub module
75
+ 4. Check whether the host already sets `HubKernel::Interface.person_method` and
76
+ `HubKernel::Interface.account_method`, for example for hub_kernel-mcp. If it does and
77
+ the base controller defines those same methods, ask the developer whether to rely on
78
+ them or to set `HubKernel::Api.person_method` and `HubKernel::Api.account_method`. If
79
+ it does not, set both on `HubKernel::Api`.
80
+
81
+ 5. Ask the developer which hubs to serve and at what address each answers. A hub module
59
82
  answers at its module name underscored, so `Supplies` answers at `supplies`. To use a
60
83
  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:
84
+ Every listed hub must expose methods, and no two may share an address. The served list
85
+ is the one hub_kernel-interface holds, so another interface gem in the host, such as
86
+ hub_kernel-mcp, serves the same list; set it once, through either gem.
87
+
88
+ 6. Ask the developer whether the API serves major versions, and if it does, the full
89
+ version of each major, in major.minor.patch form. Put these facts to them:
90
+ - With no majors listed, every call gets the method's own answer, a call that names a
91
+ major is answered as though it named none, and the API reports no version.
92
+ - With majors listed, a call or listing that names no major is answered at the oldest
93
+ major listed that is not retired, so listing majors on a host with existing clients
94
+ changes the answers and the answer shapes those clients receive unless that major is
95
+ the one they were built against.
96
+ - A major marked `retired: true` stays listed, and every call or listing that names it
97
+ is answered with status 410.
98
+ - A major marked `deprecated: true` is still answered, and every answer at it gives the
99
+ caller its `deprecated_on:` date and its `sunset:` date.
100
+ - `deprecated_on:` and `sunset:` on a major not marked `deprecated: true` are never sent
101
+ to a caller.
102
+ - `HubKernel::Api.check!` refuses to boot the host when the list holds any of these:
103
+ a version not a string in major.minor.patch form, a major listed twice, a deprecated major
104
+ missing `deprecated_on:` or `sunset:`, a `deprecated_on:` or `sunset:` that is not a
105
+ `Date`, or every listed major retired.
106
+ - It also refuses when a served hub declares an earlier answer for a major the host
107
+ does not list, or for the newest major listed. Ask the developer which majors their
108
+ hubs already declare earlier answers for, and list each of those majors.
109
+
110
+ Ask which majors, if any, are deprecated, and for each one the date it was deprecated
111
+ and the date it stops being served; both dates are required. Ask which majors, if any,
112
+ are retired, and keep at least one not retired. Do not mark a major deprecated or
113
+ retired without the developer's word: deprecating one tells every client built against
114
+ it to move, and retiring one stops every such client getting answers.
115
+
116
+ 7. Create `config/initializers/hub_kernel_api.rb` with the answers from steps 3 to 6:
64
117
 
65
118
  ```ruby
66
119
  HubKernel::Api.base_controller = "Api::HubBaseController"
67
120
  HubKernel::Api.person_method = :current_person
68
121
  HubKernel::Api.account_method = :current_account
122
+ HubKernel::Api.versions = [
123
+ HubKernel::Api::MajorVersion.new(version: "1.4.0", retired: true),
124
+ HubKernel::Api::MajorVersion.new(version: "2.0.1", deprecated: true, deprecated_on: Date.new(2026, 9, 30), sunset: Date.new(2027, 3, 31)),
125
+ HubKernel::Api::MajorVersion.new(version: "3.1.0")
126
+ ]
69
127
 
70
128
  Rails.application.config.to_prepare do
71
129
  HubKernel::Api.hubs = [ Supplies, { "money" => Billing::Ledger } ]
@@ -73,37 +131,80 @@ in when a Rails app needs its hubs callable over HTTP.
73
131
  end
74
132
  ```
75
133
 
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.
134
+ - `base_controller`, `person_method`, `account_method` and `versions` go at the top of
135
+ the file, outside `to_prepare`. The base controller name is read once, when the
136
+ API's controllers load, so it must be set before then.
137
+ - Leave out the `versions` line when the developer chose to serve no majors.
138
+ - Add `deprecated: true` only to the majors the developer named as deprecated.
139
+ - Add `deprecated_on:` and `sunset:` to each of them, as `Date` values, with the dates
140
+ the developer gave.
141
+ - Add `retired: true` only to the majors the developer named as retired.
79
142
  - `hubs` and `check!` go inside `to_prepare`, so the hub constants resolve after each
80
143
  code reload and the check runs again after each one.
81
144
 
82
- 6. Ask the developer the path to mount the API at, then add the mount to
145
+ 8. Ask the developer the path to mount the API at, then add the mount to
83
146
  `config/routes.rb`:
84
147
 
85
148
  ```ruby
86
149
  mount HubKernel::Api::Engine => "/api/v1/hubs"
87
150
  ```
88
151
 
89
- 7. Boot the app, for example with `bin/rails runner "puts :ok"`. A
152
+ 9. Boot the app, for example with `bin/rails runner "puts :ok"`. A
90
153
  `HubKernel::Api::UnservableHubError` at boot names each problem:
91
154
  - `<Hub> exposes no methods to serve` — the entry is not a hub with exposed methods;
92
155
  remove it, or expose methods on it.
93
156
  - `<Hub> and <Hub> both answer at <address>` — give one of them its own address with
94
157
  a one-pair Hash.
158
+ - `The listed version <version> is not in major.minor.patch form` — write that
159
+ entry's `version:` as a string such as `"2.1.0"`.
160
+ - `Major <n> is listed more than once` — keep one entry for that major.
161
+ - `Major <n> is deprecated with no deprecated_on: date it was deprecated` or
162
+ `... with no sunset: date it stops being served` — ask the developer for the missing
163
+ date and add it.
164
+ - `Major <n> gives deprecated_on: as <value>, which is not a Date` or the same for
165
+ `sunset:` — write the date as `Date.new(year, month, day)`.
166
+ - `Every listed major is retired, ...` — ask the developer which major to stop
167
+ retiring, or which new major to list.
168
+ - `<Hub> declares an earlier answer to <method> for major <n>, which the host does not
169
+ list` — ask the developer whether to list that major or have the hub's earlier answer
170
+ removed.
171
+ - `<Hub> declares an earlier answer to <method> for major <n>, the newest major, ...` —
172
+ ask the developer whether to list a newer major or have that earlier answer removed.
95
173
  - Any other line is a problem the hub reports with its own list of exposed methods;
96
174
  fix it in the hub.
97
175
 
176
+ Every problem is named in the one error, so fix them all before booting again.
177
+
98
178
  ## Conventions
99
179
 
100
180
  - Run `bin/rails routes` after mounting and confirm the engine appears at the chosen path.
101
181
  - To serve another hub later, add it to the `hubs` list inside `to_prepare` and boot
102
182
  again so `check!` runs.
183
+ - To serve a new major, add a `HubKernel::Api::MajorVersion` to `versions`.
184
+ - To warn clients that a major will stop being served, add `deprecated: true`,
185
+ `deprecated_on:` with the date it was deprecated, and `sunset:` with the date it stops
186
+ being served. Retire it on that date; nothing retires it when the date passes.
187
+ - To stop serving a major, ask the developer whether to retire it or remove it. Adding
188
+ `retired: true` keeps it listed, and every call that names it answers with status 410
189
+ and a message naming the newest major. Removing it while others stay listed makes every
190
+ call that names it answer with status 406, the same as a major never listed.
191
+ - Retiring or removing the oldest major that is not retired moves every call that names
192
+ no major to the next oldest one.
193
+ - Removing every major turns versioning off, and calls that name a major get the
194
+ method's own answer.
195
+ - Removing a major that a served hub declares an earlier answer for, or removing the
196
+ newest major while a hub declares an earlier answer for the one below it, stops the host
197
+ booting; boot again after every change to `versions` so `check!` runs.
198
+ - With no majors listed, `check!` checks none of the version rules.
103
199
  - 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.
200
+ - Keep `HubKernel::Api.check!` in the initializer; without it a hub that cannot be served,
201
+ or a mistake in `versions`, is found only when a client calls the API.
106
202
  - Setting the permission check and account scope is out of scope here; it belongs to
107
203
  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.
204
+ - Declaring a method's answers at earlier majors is out of scope here; it belongs to
205
+ hub_kernel-interface.
206
+ - When a listed major's minor must be raised in `versions`, because that major's answers
207
+ gained something, is out of scope here; it belongs to the develop local.
208
+ - Calling the API, naming a major on a call, its responses, its error statuses and
209
+ writing each major's description file are out of scope here; they belong to the
210
+ develop local.
@@ -6,20 +6,46 @@ install:
6
6
  - HubKernel::Api.person_method=
7
7
  - HubKernel::Api.account_method=
8
8
  - HubKernel::Api.hubs=
9
+ - HubKernel::Api.versions=
10
+ - HubKernel::Api::MajorVersion
9
11
  - HubKernel::Api.check!
10
12
  - HubKernel::Api::UnservableHubError
13
+ - HubKernel::Api::UnservedMajorError
14
+ - HubKernel::Api::RetiredMajorError
11
15
  - mount HubKernel::Api::Engine
12
16
 
13
17
  develop:
18
+ - GET /
14
19
  - GET /<hub>
15
20
  - GET /<hub>/<method>
16
21
  - POST /<hub>/<method>
22
+ - Accept-Version
23
+ - Api-Version
24
+ - Api-Newest-Version
25
+ - Deprecation
26
+ - Sunset
27
+ - Vary
28
+ - answer_shape
29
+ - bin/rails hub_kernel_api:describe
30
+ - bin/rails hub_kernel_api:check_descriptions
31
+ - HubKernel::Api::BreakingChangeError
32
+ - api_descriptions/v<major>.json
33
+ - HubKernel::Api::TestHelper
34
+ - assert_answer_shape
17
35
 
18
36
  sources:
19
37
  - lib/hub_kernel/api.rb
20
38
  - lib/hub_kernel/api/engine.rb
39
+ - lib/hub_kernel/api/major_version.rb
40
+ - lib/hub_kernel/api/description.rb
41
+ - lib/hub_kernel/api/description_files.rb
42
+ - lib/hub_kernel/api/description_check.rb
43
+ - lib/hub_kernel/api/earlier_answers.rb
44
+ - lib/hub_kernel/api/test_helper.rb
45
+ - lib/tasks/hub_kernel_api.rake
21
46
  - config/routes.rb
22
47
  - app/controllers/hub_kernel/api/hub_controller.rb
23
48
  - app/controllers/hub_kernel/api/hubs_controller.rb
24
49
  - app/controllers/hub_kernel/api/hub_calls_controller.rb
50
+ - app/controllers/hub_kernel/api/versions_controller.rb
25
51
  - 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.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.9'
32
+ version: '0.10'
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.9'
39
+ version: '0.10'
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.'
@@ -52,11 +52,19 @@ files:
52
52
  - app/controllers/hub_kernel/api/hub_calls_controller.rb
53
53
  - app/controllers/hub_kernel/api/hub_controller.rb
54
54
  - app/controllers/hub_kernel/api/hubs_controller.rb
55
+ - app/controllers/hub_kernel/api/versions_controller.rb
55
56
  - config/routes.rb
56
57
  - lib/hub_kernel-api.rb
57
58
  - lib/hub_kernel/api.rb
59
+ - lib/hub_kernel/api/description.rb
60
+ - lib/hub_kernel/api/description_check.rb
61
+ - lib/hub_kernel/api/description_files.rb
62
+ - lib/hub_kernel/api/earlier_answers.rb
58
63
  - lib/hub_kernel/api/engine.rb
64
+ - lib/hub_kernel/api/major_version.rb
65
+ - lib/hub_kernel/api/test_helper.rb
59
66
  - lib/hub_kernel/api/version.rb
67
+ - lib/tasks/hub_kernel_api.rake
60
68
  - the_local/agents/hub_kernel-api-develop.md
61
69
  - the_local/agents/hub_kernel-api-info.md
62
70
  - the_local/agents/hub_kernel-api-install.md