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.
- checksums.yaml +4 -4
- data/.gitignore +3 -8
- data/README.md +3 -422
- data/Rakefile +17 -7
- data/benchmarks/performance_compare.rb +27 -6
- data/doc/cs/client-examples.md +535 -0
- data/doc/cs/create-client.md +118 -0
- data/doc/cs/json-schema.html +1182 -0
- data/doc/cs/protocol.md +595 -0
- data/doc/cs/readme.md +432 -0
- data/doc/cs/typed-input-validation.md +122 -0
- data/doc/{client-examples.md → en/client-examples.md} +20 -10
- data/doc/{documentation-ui.md → en/documentation-ui.md} +42 -6
- data/doc/{performance.md → en/performance.md} +11 -0
- data/doc/{protocol.md → en/protocol.md} +2 -2
- data/doc/en/readme.md +423 -0
- data/haveapi.gemspec +2 -2
- data/lib/haveapi/client_example.rb +18 -5
- data/lib/haveapi/client_examples/curl.rb +5 -5
- data/lib/haveapi/client_examples/dynamic_helpers.rb +10 -10
- data/lib/haveapi/client_examples/go_client.rb +1 -1
- data/lib/haveapi/client_examples/http.rb +4 -4
- data/lib/haveapi/client_examples/js_client.rb +10 -10
- data/lib/haveapi/client_examples/php_client.rb +24 -25
- data/lib/haveapi/client_examples/python_client.rb +11 -11
- data/lib/haveapi/client_examples/ruby_cli.rb +6 -9
- data/lib/haveapi/client_examples/ruby_client.rb +24 -16
- data/lib/haveapi/client_examples/rust_client.rb +1 -1
- data/lib/haveapi/client_examples/ts_generated_client.rb +1 -1
- data/lib/haveapi/documentation_context.rb +14 -2
- data/lib/haveapi/documentation_helpers.rb +92 -15
- data/lib/haveapi/documentation_locale.rb +65 -0
- data/lib/haveapi/documentation_oauth.rb +12 -12
- data/lib/haveapi/documentation_search.rb +5 -5
- data/lib/haveapi/documentation_validators.rb +43 -33
- data/lib/haveapi/locales/cs.yml +468 -0
- data/lib/haveapi/locales/en.yml +467 -0
- data/lib/haveapi/public/css/documentation.css +8 -4
- data/lib/haveapi/public/js/documentation.js +73 -20
- data/lib/haveapi/server.rb +32 -47
- data/lib/haveapi/shared_documentation_helpers.rb +53 -5
- data/lib/haveapi/version.rb +1 -1
- data/lib/haveapi/views/doc_layout.erb +3 -2
- data/lib/haveapi/views/doc_sidebars/create-client.erb +10 -10
- data/lib/haveapi/views/doc_sidebars/json-schema.erb +2 -2
- data/lib/haveapi/views/doc_sidebars/protocol.erb +24 -24
- data/lib/haveapi/views/documentation/search_form.erb +5 -4
- data/lib/haveapi/views/documentation/search_results.erb +6 -6
- data/lib/haveapi/views/index.erb +3 -3
- data/lib/haveapi/views/main_layout.erb +4 -4
- data/lib/haveapi/views/shared_documentation.erb +8 -5
- data/lib/haveapi/views/shared_sidebar.erb +11 -11
- data/lib/haveapi/views/version_page/auth_body.erb +7 -7
- data/lib/haveapi/views/version_page/client_auth.erb +1 -1
- data/lib/haveapi/views/version_page/client_example.erb +1 -1
- data/lib/haveapi/views/version_page/client_init.erb +1 -1
- data/lib/haveapi/views/version_page/client_overview.erb +7 -5
- data/lib/haveapi/views/version_page/example_panels.erb +5 -2
- data/lib/haveapi/views/version_page/resource_body.erb +24 -24
- data/lib/haveapi/views/version_page/resource_directory.erb +2 -2
- data/lib/haveapi/views/version_page/usage.erb +5 -5
- data/lib/haveapi/views/version_page.erb +11 -11
- data/lib/haveapi/views/version_sidebar/auth_nav.erb +2 -2
- data/lib/haveapi/views/version_sidebar/authentication_control.erb +8 -8
- data/lib/haveapi/views/version_sidebar/authentication_status.erb +1 -1
- data/lib/haveapi/views/version_sidebar/brand.erb +16 -5
- data/lib/haveapi/views/version_sidebar.erb +33 -18
- data/spec/client_examples/assets/documentation_test.cjs +107 -9
- data/spec/client_examples/comment_capture.rb +72 -0
- data/spec/client_examples/comments_spec.rb +162 -0
- data/spec/client_examples/context_spec.rb +18 -2
- data/spec/client_examples/detail_spec.rb +68 -0
- data/spec/documentation/client_overview_spec.rb +60 -0
- data/spec/documentation/example_selection_spec.rb +192 -0
- data/spec/documentation/language_settings_spec.rb +132 -0
- data/spec/documentation/locale_spec.rb +367 -0
- data/spec/documentation/navigation_spec.rb +61 -3
- data/spec/documentation/oauth_spec.rb +42 -0
- data/spec/documentation/search_index_routes_spec.rb +8 -4
- data/spec/documentation/search_spec.rb +1 -1
- data/spec/documentation/shared_pages_spec.rb +63 -2
- data/spec/documentation/validators_spec.rb +25 -0
- data/spec/extensions/exception_mailer_spec.rb +2 -2
- data/spec/packaging_spec.rb +68 -9
- data/spec/performance/event_baseline_spec.rb +1 -1
- data/spec/performance/source_versions_spec.rb +111 -2
- metadata +24 -11
- /data/doc/{create-client.md → en/create-client.md} +0 -0
- /data/doc/{documentation-oauth.md → en/documentation-oauth.md} +0 -0
- /data/doc/{json-schema.html → en/json-schema.html} +0 -0
- /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](
|
|
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.
|
|
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](
|
|
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](
|
|
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](
|
|
392
|
-
[TypeScript documentation specs](
|
|
393
|
-
[Rust development checks](
|
|
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](
|
|
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](
|
|
541
|
+
described in [utils/highlight](../../utils/highlight/README.md).
|