haveapi 0.32.1 → 0.32.2

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -8
  3. data/README.md +3 -422
  4. data/Rakefile +17 -7
  5. data/benchmarks/performance_compare.rb +27 -6
  6. data/doc/cs/client-examples.md +535 -0
  7. data/doc/cs/create-client.md +118 -0
  8. data/doc/cs/json-schema.html +1182 -0
  9. data/doc/cs/protocol.md +595 -0
  10. data/doc/cs/readme.md +432 -0
  11. data/doc/cs/typed-input-validation.md +122 -0
  12. data/doc/{client-examples.md → en/client-examples.md} +20 -10
  13. data/doc/{documentation-ui.md → en/documentation-ui.md} +42 -6
  14. data/doc/{performance.md → en/performance.md} +11 -0
  15. data/doc/{protocol.md → en/protocol.md} +2 -2
  16. data/doc/en/readme.md +423 -0
  17. data/haveapi.gemspec +2 -2
  18. data/lib/haveapi/client_example.rb +18 -5
  19. data/lib/haveapi/client_examples/curl.rb +5 -5
  20. data/lib/haveapi/client_examples/dynamic_helpers.rb +10 -10
  21. data/lib/haveapi/client_examples/go_client.rb +1 -1
  22. data/lib/haveapi/client_examples/http.rb +4 -4
  23. data/lib/haveapi/client_examples/js_client.rb +10 -10
  24. data/lib/haveapi/client_examples/php_client.rb +24 -25
  25. data/lib/haveapi/client_examples/python_client.rb +11 -11
  26. data/lib/haveapi/client_examples/ruby_cli.rb +6 -9
  27. data/lib/haveapi/client_examples/ruby_client.rb +24 -16
  28. data/lib/haveapi/client_examples/rust_client.rb +1 -1
  29. data/lib/haveapi/client_examples/ts_generated_client.rb +1 -1
  30. data/lib/haveapi/documentation_context.rb +14 -2
  31. data/lib/haveapi/documentation_helpers.rb +92 -15
  32. data/lib/haveapi/documentation_locale.rb +65 -0
  33. data/lib/haveapi/documentation_oauth.rb +12 -12
  34. data/lib/haveapi/documentation_search.rb +5 -5
  35. data/lib/haveapi/documentation_validators.rb +43 -33
  36. data/lib/haveapi/locales/cs.yml +468 -0
  37. data/lib/haveapi/locales/en.yml +467 -0
  38. data/lib/haveapi/public/css/documentation.css +8 -4
  39. data/lib/haveapi/public/js/documentation.js +73 -20
  40. data/lib/haveapi/server.rb +32 -47
  41. data/lib/haveapi/shared_documentation_helpers.rb +53 -5
  42. data/lib/haveapi/version.rb +1 -1
  43. data/lib/haveapi/views/doc_layout.erb +3 -2
  44. data/lib/haveapi/views/doc_sidebars/create-client.erb +10 -10
  45. data/lib/haveapi/views/doc_sidebars/json-schema.erb +2 -2
  46. data/lib/haveapi/views/doc_sidebars/protocol.erb +24 -24
  47. data/lib/haveapi/views/documentation/search_form.erb +5 -4
  48. data/lib/haveapi/views/documentation/search_results.erb +6 -6
  49. data/lib/haveapi/views/index.erb +3 -3
  50. data/lib/haveapi/views/main_layout.erb +4 -4
  51. data/lib/haveapi/views/shared_documentation.erb +8 -5
  52. data/lib/haveapi/views/shared_sidebar.erb +11 -11
  53. data/lib/haveapi/views/version_page/auth_body.erb +7 -7
  54. data/lib/haveapi/views/version_page/client_auth.erb +1 -1
  55. data/lib/haveapi/views/version_page/client_example.erb +1 -1
  56. data/lib/haveapi/views/version_page/client_init.erb +1 -1
  57. data/lib/haveapi/views/version_page/client_overview.erb +7 -5
  58. data/lib/haveapi/views/version_page/example_panels.erb +5 -2
  59. data/lib/haveapi/views/version_page/resource_body.erb +24 -24
  60. data/lib/haveapi/views/version_page/resource_directory.erb +2 -2
  61. data/lib/haveapi/views/version_page/usage.erb +5 -5
  62. data/lib/haveapi/views/version_page.erb +11 -11
  63. data/lib/haveapi/views/version_sidebar/auth_nav.erb +2 -2
  64. data/lib/haveapi/views/version_sidebar/authentication_control.erb +8 -8
  65. data/lib/haveapi/views/version_sidebar/authentication_status.erb +1 -1
  66. data/lib/haveapi/views/version_sidebar/brand.erb +16 -5
  67. data/lib/haveapi/views/version_sidebar.erb +33 -18
  68. data/spec/client_examples/assets/documentation_test.cjs +107 -9
  69. data/spec/client_examples/comment_capture.rb +72 -0
  70. data/spec/client_examples/comments_spec.rb +162 -0
  71. data/spec/client_examples/context_spec.rb +18 -2
  72. data/spec/client_examples/detail_spec.rb +68 -0
  73. data/spec/documentation/client_overview_spec.rb +60 -0
  74. data/spec/documentation/example_selection_spec.rb +192 -0
  75. data/spec/documentation/language_settings_spec.rb +132 -0
  76. data/spec/documentation/locale_spec.rb +367 -0
  77. data/spec/documentation/navigation_spec.rb +61 -3
  78. data/spec/documentation/oauth_spec.rb +42 -0
  79. data/spec/documentation/search_index_routes_spec.rb +8 -4
  80. data/spec/documentation/search_spec.rb +1 -1
  81. data/spec/documentation/shared_pages_spec.rb +63 -2
  82. data/spec/documentation/validators_spec.rb +25 -0
  83. data/spec/extensions/exception_mailer_spec.rb +2 -2
  84. data/spec/packaging_spec.rb +68 -9
  85. data/spec/performance/event_baseline_spec.rb +1 -1
  86. data/spec/performance/source_versions_spec.rb +111 -2
  87. metadata +24 -11
  88. /data/doc/{create-client.md → en/create-client.md} +0 -0
  89. /data/doc/{documentation-oauth.md → en/documentation-oauth.md} +0 -0
  90. /data/doc/{json-schema.html → en/json-schema.html} +0 -0
  91. /data/doc/{typed-input-validation.md → en/typed-input-validation.md} +0 -0
data/doc/cs/readme.md ADDED
@@ -0,0 +1,432 @@
1
+ <h1 id="haveapi">HaveAPI</h1>
2
+
3
+ Serverová implementace protokolu [HaveAPI](https://github.com/vpsfreecz/haveapi)
4
+ v Ruby má podobu frameworku pro tvorbu RESTful webových API, která poskytují
5
+ vlastní popis. Framework obsahuje DSL pro definici zdrojů, akcí a vstupních
6
+ i výstupních parametrů. HaveAPI zajišťuje HTTP komunikaci, autentizaci,
7
+ zpracování vstupních parametrů i formátování výstupu, takže se můžeš soustředit
8
+ na aplikační logiku.
9
+
10
+ <h2 id="server-framework-features">Funkce serverového frameworku</h2>
11
+
12
+ - Zajišťuje síťovou komunikaci, autentizaci, autorizaci, vstupní a výstupní
13
+ formáty i parametry; stačí definovat zdroje a akce
14
+ - Dokumentace vzniká společně s kódem
15
+ - Automaticky generovaná online HTML dokumentace
16
+ - Integrace s ORM
17
+ - ActiveRecord
18
+ - propojení s řadičem
19
+ - načítání a dokumentování validátorů z modelů
20
+ - přednačítání souvisejících dat
21
+ - snadné doplnění podpory dalších ORM frameworků
22
+
23
+ <h2 id="usage">Použití</h2>
24
+
25
+ Text nemusí být úplný ani aktuální, protože se rozhraní stále často mění.
26
+ Příkladem plného využití HaveAPI je
27
+ [vpsadmin-api](https://github.com/vpsfreecz/vpsadmin-api)
28
+ ([online dokumentace](https://api.vpsfree.cz)).
29
+
30
+ Všechny zdroje a akce představují třídy. Musí být uložené v modulu, jehož
31
+ název se předá HaveAPI. Framework pak projde třídy v tomto modulu a sestaví API.
32
+
33
+ V tomto dokumentu budou všechny zdroje v modulu `MyAPI`.
34
+
35
+ <h3 id="example">Příklad</h3>
36
+
37
+ Základní příklad neukazuje všechny možnosti a funkce.
38
+
39
+ Předpokládejme tento model:
40
+
41
+ ```ruby
42
+ class User < ActiveRecord::Base
43
+ validates :login, :full_name, :role, presence: true
44
+ validates :login, format: {
45
+ with: /[a-zA-Z\.\-]{3,30}/,
46
+ message: 'not a valid login'
47
+ }, uniqueness: true
48
+ validates :role, inclusion: {
49
+ in: %w(admin user),
50
+ message '%{value} is not a valid role'
51
+ }
52
+
53
+ # Příklad autentizace s heslem v prostém textu
54
+ def self.authenticate(username, password)
55
+ u = User.find_by(login: username)
56
+
57
+ if u
58
+ u if u.password == password
59
+ end
60
+ end
61
+ end
62
+ ```
63
+
64
+ Zdroj pro uživatele může vypadat takto:
65
+
66
+ ```ruby
67
+ module MyAPI
68
+ class User < HaveAPI::Resource
69
+ # Tento zdroj patří do verze 1.
70
+ # Zdroj může patřit i do více verzí, například [1, 2]
71
+ version 1
72
+
73
+ # Popis zdroje
74
+ desc 'Manage users'
75
+
76
+ # Model ActiveRecord, ze kterého se načtou validátory
77
+ model ::User
78
+
79
+ # Vyžadovat autentizaci; jde o výchozí nastavení
80
+ auth true
81
+
82
+ # Pojmenovaná skupina sdílených parametrů, kterou pak mohou
83
+ # použít akce.
84
+ params(:id) do
85
+ id :id, label: 'User ID'
86
+ end
87
+
88
+ params(:common) do
89
+ string :login, label: 'Login', desc: 'Used for authentication'
90
+ string :full_name, label: 'Full name'
91
+ string :role, label: 'User role', desc: 'admin or user'
92
+ end
93
+
94
+ # Akce
95
+ # Modul HaveAPI::Actions::Default obsahuje pomocné třídy, které definují
96
+ # HTTP metody a cesty pro obecné akce.
97
+ class Index < HaveAPI::Actions::Default::Index
98
+ desc 'List all users'
99
+
100
+ # Žádné vstupní parametry
101
+
102
+ # Výstupní parametry
103
+ output(:object_list) do
104
+ use :id
105
+ use :common
106
+ end
107
+
108
+ # Určení, zda může aktuální uživatel tuto akci použít.
109
+ # allow/deny ihned ukončí tento blok.
110
+ # Výchozím pravidlem je deny.
111
+ authorize do |u|
112
+ allow if u.role == 'admin'
113
+ deny # deny je implicitní, takže ho lze vynechat
114
+ end
115
+
116
+ # Příklad použití
117
+ example do
118
+ request({})
119
+ response({
120
+ users: [
121
+ {
122
+ id: 1,
123
+ login: 'myuser',
124
+ full_name: 'My Very Name'
125
+ }
126
+ ]
127
+ })
128
+ comment 'Get a list of all users like this'
129
+ end
130
+
131
+ # Pomocná metoda vracející dotaz na všechny uživatele
132
+ def query
133
+ ::User.all
134
+ end
135
+
136
+ # Tato metoda se volá, pokud požadavek obsahuje meta[:count] = true
137
+ def count
138
+ query.count
139
+ end
140
+
141
+ # Provedení akce a vrácení seznamu
142
+ def exec
143
+ with_pagination(query)
144
+ end
145
+ end
146
+
147
+ class Create < HaveAPI::Actions::Default::Create
148
+ desc 'Create new user'
149
+
150
+ input do
151
+ use :common
152
+ end
153
+
154
+ output do
155
+ use :id
156
+ use :common
157
+ end
158
+
159
+ authorize do |u|
160
+ allow if u.role == 'admin'
161
+ deny
162
+ end
163
+
164
+ example do
165
+ request({
166
+ user: {
167
+ login: 'anotherlogin',
168
+ full_name: 'My Very New Name'
169
+ }
170
+ })
171
+ response({
172
+ user: {
173
+ id: 2
174
+ }
175
+ })
176
+ comment 'Create new user like this'
177
+ end
178
+
179
+ def exec
180
+ user = ::User.new(input)
181
+
182
+ if user.save
183
+ ok!(user)
184
+ else
185
+ error!('save failed', user.errors.to_hash)
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+ ```
192
+
193
+ <h3 id="what-you-get">Výsledek</h3>
194
+
195
+ Z tohoto kódu HaveAPI vygeneruje API s vlastním popisem. Bude obsahovat zdroj
196
+ `User` s akcemi `Index` a `Create`, kterými můžeš vypsat existující uživatele
197
+ a vytvářet nové.
198
+
199
+ S API můžeš pracovat pomocí kteréhokoli z dostupných klientů.
200
+
201
+ <h3 id="run-the-example">Spuštění příkladu</h3>
202
+
203
+ ```ruby
204
+ api = HaveAPI::Server.new(MyAPI)
205
+
206
+ # Použití HTTP Basic autentizace
207
+ class BasicAuth < HaveAPI::Authentication::Basic::Provider
208
+ def find_user(request, username, password)
209
+ User.authenticate(username, password)
210
+ end
211
+ end
212
+
213
+ api.use_version(:all)
214
+ api.auth_chain << BasicAuth
215
+ api.mount('/')
216
+
217
+ api.start!
218
+ ```
219
+
220
+ Tím by se měla aplikace spustit pomocí WEBrick. Otevři
221
+ [http://localhost:4567](http://localhost:4567).
222
+
223
+ - `GET /` – seznam verzí API
224
+ - `GET /doc` – dokumentace HaveAPI
225
+ - `GET /v1/` – dokumentace verze 1
226
+ - `OPTIONS /` – popis celého API
227
+ - `OPTIONS /v1/` – popis verze API 1
228
+
229
+ a další rozhraní.
230
+
231
+ <h2 id="localization">Lokalizace</h2>
232
+
233
+ HaveAPI může pomocí Ruby `i18n` překládat vlastní zprávy v odpovědích,
234
+ validační chyby a popisy validátorů. Struktura JSON obálky zůstává stejná;
235
+ `message`, `errors` i zprávy validátorů v popisu API jsou nadále obyčejné
236
+ řetězce. Řetězce dodané aplikací do `error!` nebo do voleb `message:` vlastních
237
+ validátorů se vracejí beze změny.
238
+
239
+ Výchozím jazykem je angličtina. Součástí jsou české překlady, které lze vybrat
240
+ hlavičkou `Accept-Language: cs` nebo regionální variantou, například
241
+ `Accept-Language: cs-CZ`.
242
+
243
+ ```ruby
244
+ api = HaveAPI::Server.new(MyAPI)
245
+
246
+ api.default_locale = :en
247
+ api.available_locales = %i[en cs]
248
+ api.locale_header = 'Accept-Language'
249
+
250
+ api.locale do |request:, current_user:, default_locale:|
251
+ current_user&.language&.code || default_locale
252
+ end
253
+ ```
254
+
255
+ Explicitní hlavička požadavku má přednost před resolverem. Resolver se volá
256
+ znovu po autentizaci, takže aplikace může použít jazykové nastavení
257
+ přihlášeného uživatele, pokud klient jazyk nezvolil. Pokud `locale_header`
258
+ určuje vlastní název hlavičky, HaveAPI ji také povolí v odpovědích na CORS
259
+ preflight požadavky. Hodnota hlavičky má stejnou syntaxi jako `Accept-Language`.
260
+
261
+ Akce mohou používat překlady aplikace předáním odložených zpráv do `error!`
262
+ nebo do voleb validátoru:
263
+
264
+ ```ruby
265
+ error!(api_message('my_api.errors.quota_exceeded', limit: max_limit))
266
+
267
+ input do
268
+ string :name, required: {
269
+ message: HaveAPI.message('my_api.validation.name_required')
270
+ }
271
+ end
272
+ ```
273
+
274
+ Pokud akce potřebuje překlad ihned jako řetězec, použij `api_t(key, **values)`.
275
+ V DSL blocích na úrovni třídy, například `input`, použij
276
+ `HaveAPI.message(key, **values)`.
277
+
278
+ Popisky a popisy parametrů akcí se mohou překládat v kontextu popisu API.
279
+ Nastav `parameter_i18n_scope` na jmenný prostor překladů aplikace a ponech
280
+ stávající anglické popisky a popisy jako náhradní hodnoty:
281
+
282
+ ```ruby
283
+ api.parameter_i18n_scope = 'my_api'
284
+
285
+ input do
286
+ string :hostname,
287
+ label: 'Hostname',
288
+ desc: 'VPS hostname'
289
+ end
290
+ ```
291
+
292
+ HaveAPI nejprve hledá přesný klíč parametru akce:
293
+
294
+ ```yaml
295
+ cs:
296
+ my_api:
297
+ resources:
298
+ vps:
299
+ actions:
300
+ create:
301
+ input:
302
+ hostname:
303
+ label: "Hostname"
304
+ description: "Nazev VPS"
305
+ ```
306
+
307
+ Vygenerovaná cesta je
308
+ `resources.<resource_path>.actions.<action>.<input|output>.<name>`.
309
+ U parametrů metadat zahrnuje také typ metadat a směr, například
310
+ `resources.vps.actions.create.meta.global.output.action_state_id.label`.
311
+
312
+ Pokud přesný klíč chybí, HaveAPI hledá mezi vstupními a výstupními klíči
313
+ zdroje, atributy zdroje a nakonec sdílenými atributy:
314
+
315
+ ```yaml
316
+ cs:
317
+ my_api:
318
+ resources:
319
+ vps:
320
+ input:
321
+ hostname:
322
+ label: "Hostname"
323
+ description: "Nazev VPS"
324
+ output:
325
+ hostname:
326
+ label: "Hostname"
327
+ attributes:
328
+ hostname:
329
+ label: "Hostname"
330
+ attributes:
331
+ hostname:
332
+ label: "Hostname"
333
+ ```
334
+
335
+ Popisky voleb deklarovaných validátorem `choices`/`include` používají stejnou
336
+ cestu metadat parametru s připojeným `choices.<value>.label`. Pokud jsou volby
337
+ zadané jako mapa hodnot na popisky, použije se deklarovaný popisek jako
338
+ anglická náhradní hodnota. Pokud jsou zadané jako pole, nepřeložený popis API
339
+ zachová formát pole; jazyk, který poskytuje popisky, vrací existující formát
340
+ mapy HaveAPI `{value: label}`.
341
+
342
+ ```yaml
343
+ cs:
344
+ my_api:
345
+ resources:
346
+ vps:
347
+ attributes:
348
+ state:
349
+ choices:
350
+ running:
351
+ label: "bezi"
352
+ stopped:
353
+ label: "vypnuto"
354
+ ```
355
+
356
+ U parametrů metadat se jako náhrada hledají klíče metadat zdroje a globálních metadat:
357
+
358
+ ```yaml
359
+ cs:
360
+ my_api:
361
+ resources:
362
+ vps:
363
+ meta:
364
+ global:
365
+ output:
366
+ count:
367
+ label: "Return item count"
368
+ meta:
369
+ global:
370
+ output:
371
+ count:
372
+ label: "Return item count"
373
+ ```
374
+
375
+ Vlastní metadata HaveAPI, například stránkování a vestavěné meta parametry,
376
+ překládá přímo HaveAPI a nehledá je v jmenném prostoru parametrů aplikace.
377
+ Pokud parametr potřebuje explicitní klíč, který nevychází z jeho umístění
378
+ v akci, použij `label_key` a `desc_key`:
379
+
380
+ ```ruby
381
+ string :hostname,
382
+ label: 'Hostname',
383
+ desc: 'VPS hostname',
384
+ label_key: 'my_api.attributes.hostname.label',
385
+ desc_key: 'my_api.attributes.hostname.description'
386
+ ```
387
+
388
+ HaveAPI také zpřístupňuje `api.parameter_metadata_i18n_items` pro nástroje,
389
+ které z deklarovaných parametrů generují katalogy překladů aplikace.
390
+
391
+ <h3 id="run-with-rackup">Spuštění pomocí rackup</h3>
392
+
393
+ Použij stejný kód jako výše, pouze poslední řádek nahraď tímto:
394
+
395
+ ```ruby
396
+ run api.app
397
+ ```
398
+
399
+ <h2 id="authentication">Autentizace</h2>
400
+
401
+ HaveAPI definuje rozhraní pro poskytovatele autentizace. Vestavěná je HTTP
402
+ Basic autentizace a autentizace tokenem.
403
+
404
+ Možnosti autentizace jsou součástí popisu API. Klient si může zvolit metodu,
405
+ které rozumí a kterou chce použít.
406
+
407
+ <h2 id="authorization">Autorizace</h2>
408
+
409
+ HaveAPI poskytuje prostředky pro autorizaci přístupu uživatelů k akcím.
410
+ Tento proces není součástí popisu API.
411
+
412
+ Pokud je uživatel při požadavku na popis API přihlášený, vrátí se pouze
413
+ zdroje, akce a parametry, ke kterým má přístup.
414
+
415
+ <h2 id="validation-of-input-data">Validace vstupních dat</h2>
416
+
417
+ Validátory jsou součástí dokumentace API, takže klienti mohou validovat data
418
+ ještě před jejich odesláním na server.
419
+
420
+ <h2 id="blocking-actions">Blokující akce</h2>
421
+
422
+ Blokující režim slouží pro akce, jejichž provedení není okamžité a trvá
423
+ předem neurčenou dobu. Protokol HaveAPI umožňuje klientům sledovat jejich
424
+ průběh nebo je zrušit.
425
+
426
+ <h2 id="contributing">Přispívání</h2>
427
+
428
+ 1. Vytvoř fork ( https://github.com/vpsfreecz/haveapi/fork )
429
+ 2. Vytvoř větev pro svou změnu (`git checkout -b my-new-feature`)
430
+ 3. Vytvoř commit se změnami (`git commit -am 'Add some feature'`)
431
+ 4. Odešli větev (`git push origin my-new-feature`)
432
+ 5. Vytvoř nový pull request
@@ -0,0 +1,122 @@
1
+ <h1 id="typed-input-validation">Validace typovaných vstupů</h1>
2
+
3
+ <h2 id="overview">Přehled</h2>
4
+
5
+ Parametry HaveAPI deklarují `type` (String, Text, Integer, Float, Boolean, Datetime nebo Resource).
6
+ Servery i klienti MUSÍ typované vstupní parametry přísně validovat.
7
+ Neplatné hodnoty se NESMÍ tiše převádět na výchozí hodnoty jako `0`, `0.0` nebo `false`.
8
+
9
+ <h2 id="general-rules">Obecná pravidla</h2>
10
+
11
+ - Skalární typy přijímají pouze skalární hodnoty. Pole, seznamy, objekty a hashe jsou neplatné.
12
+ - Pro účely validace znamená `null`/`nil` „hodnota vynechána“ (server může použít výchozí hodnotu),
13
+ ale explicitní `null` je platný pouze u parametrů označených jako `nullable` (obvykle nepovinných).
14
+ Klienti MUSÍ explicitní `null` zachovat a odeslat jako JSON `null`, aby akce rozlišily
15
+ vynechanou hodnotu od výslovně vymazané.
16
+ - Prázdné řetězce (`""` nebo řetězce obsahující jen bílé znaky) jsou pro Integer, Float, Boolean a Datetime neplatné.
17
+ U typovaných parametrů s `nullable` (včetně ID zdrojů) se prázdný řetězec nebo bílé znaky považují
18
+ za `null`/vynechanou hodnotu. To umožňuje vyjádřit explicitní `null` v query stringu.
19
+ - Validace na straně klienta se doporučuje; rozhodující je validace serveru.
20
+
21
+ Příklad query stringu (explicitní `null` pro typovaný parametr s `nullable`):
22
+
23
+ GET /resource/action?resource[dt]=
24
+
25
+ Prázdná hodnota se u typovaných parametrů s `nullable` považuje za `null`.
26
+
27
+ <h2 id="per-type-rules-with-examples">Pravidla a příklady pro jednotlivé typy</h2>
28
+
29
+ <h3 id="integer">Integer</h3>
30
+
31
+ Přijímá:
32
+ - celé číslo v JSON (např. `12`, `-7`)
33
+ - řetězec odpovídající celému číslu v desítkové soustavě `^[+-]?\d+$` po odstranění krajních bílých znaků (např. `"42"`, `"+5"`)
34
+ - konečné číslo s plovoucí řádovou čárkou, které má celočíselnou hodnotu (např. `12.0`)
35
+
36
+ Odmítá:
37
+ - nečíselné řetězce (`"abc"`, `"12abc"`)
38
+ - desetinné řetězce (`"12.0"`) a čísla s nenulovou desetinnou částí (`12.3`)
39
+ - prázdný řetězec nebo řetězec obsahující jen bílé znaky
40
+
41
+ <h3 id="float">Float</h3>
42
+
43
+ Přijímá:
44
+ - celé číslo nebo číslo s plovoucí řádovou čárkou v JSON (pouze konečné)
45
+ - řetězec obsahující po odstranění krajních bílých znaků úplný zápis čísla, včetně exponentu (např. `"1e3"`, `"-0.5"`)
46
+
47
+ Odmítá:
48
+ - nečíselné řetězce
49
+ - prázdný řetězec nebo řetězec obsahující jen bílé znaky
50
+ - nekonečné hodnoty a hodnoty, které nejsou číslem (`NaN`, `Infinity`)
51
+
52
+ Poznámka: celá čísla se pro Float přijímají a převádějí na čísla s plovoucí řádovou čárkou.
53
+
54
+ <h3 id="boolean">Boolean</h3>
55
+
56
+ Přijímá:
57
+ - logickou hodnotu v JSON
58
+ - celé číslo `0`/`1`
59
+ - následující řetězce (bez rozlišení velikosti písmen, po odstranění krajních bílých znaků):
60
+ - pravda: `true`, `t`, `yes`, `y`, `1`
61
+ - nepravda: `false`, `f`, `no`, `n`, `0`
62
+
63
+ Odmítá:
64
+ - prázdný řetězec nebo řetězec obsahující jen bílé znaky
65
+ - neznámé řetězce (`"maybe"`)
66
+ - čísla jiná než 0/1
67
+
68
+ <h3 id="datetime">Datetime</h3>
69
+
70
+ Přijímá (přenášený formát): řetězce s datem nebo datem a časem podle ISO 8601:
71
+ - `YYYY-MM-DD`
72
+ - `YYYY-MM-DDTHH:MM(:SS(.sss)?)?(Z|+HH:MM|-HH:MM|+HHMM|-HHMM)`
73
+
74
+ Příklady: `"2020-01-31"`, `"2020-01-31T10:20Z"`, `"2020-01-31T10:20:30.123-0500"`.
75
+
76
+ Odmítá:
77
+ - prázdný řetězec nebo řetězec obsahující jen bílé znaky
78
+ - jiné formáty než ISO (`2020/01/01`)
79
+ - neplatná kalendářní data (`2020-02-30`)
80
+
81
+ Poznámka: někteří klienti mohou přijímat nativní objekty Date/Time a serializovat je do ISO 8601.
82
+
83
+ <h3 id="string-text-rule-6-b">String / Text (pravidlo 6.B)</h3>
84
+
85
+ Přijímá:
86
+ - skalární hodnoty (řetězec, číslo, logická hodnota) a převádí je na řetězec
87
+
88
+ Odmítá:
89
+ - pole a seznamy
90
+ - objekty a hashe
91
+
92
+ <h3 id="resource">Resource</h3>
93
+
94
+ V přenášených datech jsou vstupem identifikátory zdrojů.
95
+
96
+ Přijímá:
97
+ - celočíselné ID
98
+ - ID jako řetězec číslic po odstranění krajních bílých znaků
99
+ - u některých klientů ResourceInstance, ze které použije `id`
100
+ - prázdný řetězec nebo řetězec obsahující jen bílé znaky jako `null`/vynechanou hodnotu, pokud má parametr `nullable`
101
+
102
+ Odmítá:
103
+ - prázdný řetězec nebo řetězec obsahující jen bílé znaky u povinných parametrů
104
+ - řetězce obsahující jiné znaky než číslice
105
+ - záporná ID
106
+
107
+ Pokud se server pokusí zdroj dohledat a zdroj neexistuje, MUSÍ vrátit validační chybu
108
+ ("resource not found"), nikoli chybu 500.
109
+
110
+ <h2 id="error-reporting-expectations">Očekávané hlášení chyb</h2>
111
+
112
+ - Server hlásí neplatné typované hodnoty jako chyby validace parametrů ("input parameters are not valid").
113
+ - Klienti by měli pokud možno chybu zachytit ihned lokálně a hlásit ji pro jednotlivé parametry.
114
+
115
+ Doporučené jednotné zprávy používané klienty:
116
+ - `not a valid integer`
117
+ - `not a valid float`
118
+ - `not a valid boolean`
119
+ - `not in ISO 8601 format`
120
+ - `not a valid string`
121
+ - `not a valid resource ID`
122
+ - `cannot be null`
@@ -62,7 +62,7 @@ api.mount('/api/')
62
62
  `generator_version` defaults to the server's `HaveAPI::VERSION`. Install the
63
63
  matching generator in the server's Ruby environment: `haveapi-go-client`,
64
64
  `haveapi-rust-client`, or the source-distributed `haveapi-typescript-client`.
65
- See the [TypeScript generator guide](../clients/typescript/README.md) for its
65
+ See the [TypeScript generator guide](../../clients/typescript/README.md) for its
66
66
  setup. An explicit `generator_version` requires the installed generator to report
67
67
  that version; the server never downloads one. This version is independent of the
68
68
  API client and API versions.
@@ -96,7 +96,7 @@ go get example.org/widget/client@latest
96
96
  cargo add widget-client
97
97
  # Blocking Rust variant:
98
98
  cargo add widget-client --features blocking
99
- npm install @example/widget-client haveapi-client@0.30.2
99
+ npm install @example/widget-client haveapi-client@0.32.0
100
100
  ```
101
101
 
102
102
  Go resolves `@latest` by its normal rules. Cargo selects a compatible release
@@ -114,7 +114,7 @@ users can install; the server does not check its availability or publish it.
114
114
  TypeScript examples call the package's typed properties through its public
115
115
  `createClient` export. The profile does not detect or select the application's
116
116
  installed `haveapi-client` runtime. The installation command above uses the
117
- version supported by the [TypeScript generator](../clients/typescript/README.md);
117
+ version supported by the [TypeScript generator](../../clients/typescript/README.md);
118
118
  the examples do not report it as a configured runtime version.
119
119
 
120
120
  For an unpublished Rust API client, supply an HTTPS Git URL and a full commit SHA:
@@ -209,6 +209,16 @@ wire requests or persisted data.
209
209
 
210
210
  ## Renderer extensions
211
211
 
212
+ Framework-authored explanatory comments follow the documentation language.
213
+ Executable code, identifiers, literals, commented commands and sample data stay
214
+ unchanged. The immutable context captures `locale`, defaulting to `:en`, and
215
+ retains it through `with`. `example_comment(key, default:, **values)` resolves
216
+ `haveapi.documentation.comments.<key>`; `documentation_message` resolves other
217
+ keys relative to `haveapi.documentation`, including generated-client limitations.
218
+ Renderers add a comment marker to every physical prose line. Documentation
219
+ adapters can use these optional context methods without depending on the server
220
+ gem; old contexts and direct renderer calls keep English defaults.
221
+
212
222
  Existing renderer positional constructors and `init`, `auth(method, desc)` and
213
223
  `example(sample)` or `request(sample)`/`response(sample)` methods still work.
214
224
  The registry binds a request-local `HaveAPI::ClientExample::Context` through
@@ -385,17 +395,17 @@ When changing a renderer:
385
395
  - Inspect relevant initialization, authentication and action output for affected
386
396
  variants and both direct detail inputs. Cover absent optional fragments and
387
397
  literal edge cases where the change can affect them.
388
- - Use existing [server example specs](../servers/ruby/spec/client_examples/) for
398
+ - Use existing [server example specs](../../servers/ruby/spec/client_examples/) for
389
399
  PHP literal round trips and real handlers, Ruby syntax, Python AST/separation,
390
400
  detail behavior and custom whitespace. Use the owning
391
- [Go documentation specs](../clients/go/spec/unit/documentation_spec.rb),
392
- [TypeScript documentation specs](../clients/typescript/spec/unit/) and
393
- [Rust development checks](../clients/rust/docs/development.md) when affected.
401
+ [Go documentation specs](../../clients/go/spec/unit/documentation_spec.rb),
402
+ [TypeScript documentation specs](../../clients/typescript/spec/unit/) and
403
+ [Rust development checks](../../clients/rust/docs/development.md) when affected.
394
404
  TypeScript coverage includes source, strict compilation and performance specs.
395
405
  - Search neighboring HTML, fixture and performance assertions for exact source
396
406
  spelling. Update intentional quote/import/spacing expectations while retaining
397
407
  semantic assertions, traversal/allocation bounds and strict compiler checks.
398
- - Follow [development commands](agent-instructions/development.md) and the
408
+ - Follow [development commands](../agent-instructions/development.md) and the
399
409
  existing verification requirements. Select checks by affected language and
400
410
  behavior; an unrelated edit does not require every language toolchain.
401
411
 
@@ -488,7 +498,7 @@ This command runs outside Bundler and records the gem versions actually
488
498
  activated. Retain that list alongside both component locks and use the same
489
499
  prepared inputs for both revisions. Missing optional dependencies fail the run;
490
500
  Rust lanes are never silently omitted. See the
491
- [Rust adapter guide](../clients/rust/docs/documentation.md#verification).
501
+ [Rust adapter guide](../../clients/rust/docs/documentation.md#verification).
492
502
 
493
503
  Every lane reports each trial and the median wall seconds, process CPU seconds
494
504
  and allocated objects, with the operation count per trial. Wall time uses a
@@ -528,4 +538,4 @@ installed packages or an API client. These run rendered source against
528
538
  disposable fixtures; syntax checks alone do not
529
539
  establish that client calls or authentication work. See each client's
530
540
  development documentation for its test environment. Highlighter rebuilding is
531
- described in [utils/highlight](../utils/highlight/README.md).
541
+ described in [utils/highlight](../../utils/highlight/README.md).