haveapi 0.6.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 +4 -4
- data/.editorconfig +15 -0
- data/CHANGELOG +15 -0
- data/README.md +66 -47
- data/doc/create-client.md +14 -5
- data/doc/json-schema.erb +16 -2
- data/doc/protocol.md +25 -3
- data/doc/protocol.plantuml +14 -8
- data/haveapi.gemspec +4 -2
- data/lib/haveapi.rb +5 -3
- data/lib/haveapi/action.rb +34 -6
- data/lib/haveapi/action_state.rb +92 -0
- data/lib/haveapi/authentication/basic/provider.rb +7 -0
- data/lib/haveapi/authentication/token/provider.rb +5 -0
- data/lib/haveapi/client_example.rb +83 -0
- data/lib/haveapi/client_examples/curl.rb +86 -0
- data/lib/haveapi/client_examples/fs_client.rb +116 -0
- data/lib/haveapi/client_examples/http.rb +91 -0
- data/lib/haveapi/client_examples/js_client.rb +149 -0
- data/lib/haveapi/client_examples/php_client.rb +122 -0
- data/lib/haveapi/client_examples/ruby_cli.rb +117 -0
- data/lib/haveapi/client_examples/ruby_client.rb +106 -0
- data/lib/haveapi/context.rb +3 -2
- data/lib/haveapi/example.rb +29 -2
- data/lib/haveapi/extensions/action_exceptions.rb +2 -2
- data/lib/haveapi/extensions/base.rb +1 -1
- data/lib/haveapi/extensions/exception_mailer.rb +339 -0
- data/lib/haveapi/hooks.rb +1 -1
- data/lib/haveapi/parameters/typed.rb +5 -3
- data/lib/haveapi/public/css/highlight.css +99 -0
- data/lib/haveapi/public/doc/protocol.png +0 -0
- data/lib/haveapi/public/js/highlight.pack.js +2 -0
- data/lib/haveapi/public/js/highlighter.js +9 -0
- data/lib/haveapi/public/js/main.js +32 -0
- data/lib/haveapi/public/js/nojs-tabs.js +196 -0
- data/lib/haveapi/resources/action_state.rb +196 -0
- data/lib/haveapi/server.rb +96 -27
- data/lib/haveapi/version.rb +2 -2
- data/lib/haveapi/views/main_layout.erb +14 -0
- data/lib/haveapi/views/version_page.erb +187 -13
- data/lib/haveapi/views/version_sidebar.erb +37 -3
- metadata +49 -5
data/lib/haveapi/server.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'redcarpet'
|
3
|
+
require 'cgi'
|
3
4
|
|
4
5
|
module HaveAPI
|
5
6
|
class Server
|
6
7
|
attr_reader :root, :routes, :module_name, :auth_chain, :versions, :default_version,
|
7
8
|
:extensions
|
9
|
+
attr_accessor :action_state
|
8
10
|
|
9
11
|
include Hookable
|
10
12
|
|
@@ -16,6 +18,17 @@ module HaveAPI
|
|
16
18
|
current_user: 'object returned by the authentication backend',
|
17
19
|
}
|
18
20
|
|
21
|
+
has_hook :description_exception,
|
22
|
+
desc: 'Called when an exception occurs when building self-description',
|
23
|
+
args: {
|
24
|
+
context: 'HaveAPI::Context',
|
25
|
+
exception: 'exception instance',
|
26
|
+
},
|
27
|
+
ret: {
|
28
|
+
http_status: 'HTTP status code to send to client',
|
29
|
+
message: 'error message sent to the client',
|
30
|
+
}
|
31
|
+
|
19
32
|
module ServerHelpers
|
20
33
|
def authenticate!(v)
|
21
34
|
require_auth! unless authenticated?(v)
|
@@ -74,6 +87,26 @@ module HaveAPI
|
|
74
87
|
markdown :"../../../doc/#{file}"
|
75
88
|
end
|
76
89
|
|
90
|
+
def base_url
|
91
|
+
"#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def host
|
95
|
+
request.env['HTTP_HOST'].split(':').first
|
96
|
+
end
|
97
|
+
|
98
|
+
def urlescape(v)
|
99
|
+
CGI.escape(v)
|
100
|
+
end
|
101
|
+
|
102
|
+
def sort_hash(hash)
|
103
|
+
hash.sort { |a, b| a[0] <=> b[0] }
|
104
|
+
end
|
105
|
+
|
106
|
+
def api_version
|
107
|
+
@v
|
108
|
+
end
|
109
|
+
|
77
110
|
def version
|
78
111
|
HaveAPI::VERSION
|
79
112
|
end
|
@@ -122,9 +155,12 @@ module HaveAPI
|
|
122
155
|
set :views, settings.root + '/views'
|
123
156
|
set :public_folder, settings.root + '/public'
|
124
157
|
set :bind, '0.0.0.0'
|
125
|
-
|
126
|
-
|
127
|
-
|
158
|
+
|
159
|
+
if settings.development?
|
160
|
+
set :dump_errors, true
|
161
|
+
set :raise_errors, true
|
162
|
+
set :show_exceptions, false
|
163
|
+
end
|
128
164
|
|
129
165
|
helpers ServerHelpers
|
130
166
|
|
@@ -212,11 +248,12 @@ module HaveAPI
|
|
212
248
|
|
213
249
|
@sinatra.get "#{@root}doc/readme" do
|
214
250
|
content_type 'text/html'
|
251
|
+
|
215
252
|
erb :main_layout do
|
216
253
|
GitHub::Markdown.render(File.new(settings.views + '/../../../README.md').read)
|
217
254
|
end
|
218
255
|
end
|
219
|
-
|
256
|
+
|
220
257
|
@sinatra.get "#{@root}doc/json-schema" do
|
221
258
|
content_type 'text/html'
|
222
259
|
erb :doc_layout, layout: :main_layout do
|
@@ -255,7 +292,7 @@ module HaveAPI
|
|
255
292
|
@auth_chain << HaveAPI.default_authenticate if @auth_chain.empty?
|
256
293
|
@auth_chain.setup(@versions)
|
257
294
|
|
258
|
-
@extensions.each { |e| e.enabled }
|
295
|
+
@extensions.each { |e| e.enabled(self) }
|
259
296
|
|
260
297
|
# Mount default version first
|
261
298
|
mount_version(@root, @default_version)
|
@@ -279,6 +316,7 @@ module HaveAPI
|
|
279
316
|
user: current_user,
|
280
317
|
params: params
|
281
318
|
))
|
319
|
+
|
282
320
|
content_type 'text/html'
|
283
321
|
erb :doc_layout, layout: :main_layout do
|
284
322
|
@content = erb :version_page
|
@@ -298,10 +336,20 @@ module HaveAPI
|
|
298
336
|
)))
|
299
337
|
end
|
300
338
|
|
339
|
+
# Register blocking resource
|
301
340
|
HaveAPI.get_version_resources(@module_name, v).each do |resource|
|
302
341
|
mount_resource(prefix, v, resource, @routes[v][:resources])
|
303
342
|
end
|
304
343
|
|
344
|
+
if action_state
|
345
|
+
mount_resource(
|
346
|
+
prefix,
|
347
|
+
v,
|
348
|
+
HaveAPI::Resources::ActionState,
|
349
|
+
@routes[v][:resources]
|
350
|
+
)
|
351
|
+
end
|
352
|
+
|
305
353
|
validate_resources(@routes[v][:resources])
|
306
354
|
end
|
307
355
|
|
@@ -350,7 +398,11 @@ module HaveAPI
|
|
350
398
|
|
351
399
|
def mount_action(v, route)
|
352
400
|
@sinatra.method(route.http_method).call(route.url) do
|
353
|
-
|
401
|
+
if route.action.auth
|
402
|
+
authenticate!(v)
|
403
|
+
else
|
404
|
+
authenticated?(v)
|
405
|
+
end
|
354
406
|
|
355
407
|
request.body.rewind
|
356
408
|
|
@@ -370,6 +422,7 @@ module HaveAPI
|
|
370
422
|
action = route.action.new(request, v, params, body, Context.new(
|
371
423
|
settings.api_server,
|
372
424
|
version: v,
|
425
|
+
request: self,
|
373
426
|
action: route.action,
|
374
427
|
url: route.url,
|
375
428
|
params: params,
|
@@ -381,15 +434,19 @@ module HaveAPI
|
|
381
434
|
report_error(403, {}, 'Access denied. Insufficient permissions.')
|
382
435
|
end
|
383
436
|
|
384
|
-
status, reply, errors = action.safe_exec
|
437
|
+
status, reply, errors, http_status = action.safe_exec
|
438
|
+
@halted = true
|
385
439
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
440
|
+
[
|
441
|
+
http_status || 200,
|
442
|
+
@formatter.format(
|
443
|
+
status,
|
444
|
+
status ? reply : nil,
|
445
|
+
!status ? reply : nil,
|
446
|
+
errors,
|
447
|
+
version: false
|
448
|
+
),
|
449
|
+
]
|
393
450
|
end
|
394
451
|
|
395
452
|
@sinatra.options route.url do |*args|
|
@@ -398,26 +455,38 @@ module HaveAPI
|
|
398
455
|
|
399
456
|
pass if params[:method] && params[:method] != route_method
|
400
457
|
|
401
|
-
|
458
|
+
if route.action.auth
|
459
|
+
authenticate!(v)
|
460
|
+
else
|
461
|
+
authenticated?(v)
|
462
|
+
end
|
463
|
+
|
464
|
+
ctx = Context.new(
|
465
|
+
settings.api_server,
|
466
|
+
version: v,
|
467
|
+
request: self,
|
468
|
+
action: route.action,
|
469
|
+
url: route.url,
|
470
|
+
args: args,
|
471
|
+
params: params,
|
472
|
+
user: current_user,
|
473
|
+
endpoint: true
|
474
|
+
)
|
402
475
|
|
403
476
|
begin
|
404
|
-
desc = route.action.describe(
|
405
|
-
settings.api_server,
|
406
|
-
version: v,
|
407
|
-
action: route.action,
|
408
|
-
url: route.url,
|
409
|
-
args: args,
|
410
|
-
params: params,
|
411
|
-
user: current_user,
|
412
|
-
endpoint: true
|
413
|
-
))
|
477
|
+
desc = route.action.describe(ctx)
|
414
478
|
|
415
479
|
unless desc
|
416
480
|
report_error(403, {}, 'Access denied. Insufficient permissions.')
|
417
481
|
end
|
418
482
|
|
419
|
-
rescue
|
420
|
-
|
483
|
+
rescue => e
|
484
|
+
tmp = settings.api_server.call_hooks_for(:description_exception, args: [ctx, e])
|
485
|
+
report_error(
|
486
|
+
tmp[:http_status] || 500,
|
487
|
+
{},
|
488
|
+
tmp[:message] || 'Server error occured'
|
489
|
+
)
|
421
490
|
end
|
422
491
|
|
423
492
|
@formatter.format(true, desc)
|
data/lib/haveapi/version.rb
CHANGED
@@ -7,6 +7,10 @@
|
|
7
7
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
8
8
|
<script src="/js/jquery-1.11.1.min.js"></script>
|
9
9
|
<script src="/js/bootstrap.min.js"></script>
|
10
|
+
<script src="/js/nojs-tabs.js"></script>
|
11
|
+
<link rel="stylesheet" href="/css/highlight.css">
|
12
|
+
<script src="/js/highlight.pack.js"></script>
|
13
|
+
<script src="/js/main.js"></script>
|
10
14
|
|
11
15
|
<style>
|
12
16
|
/*.resource { margin-left: 10px; }*/
|
@@ -47,6 +51,16 @@
|
|
47
51
|
padding: 5px 0px;
|
48
52
|
margin-left: 18px;
|
49
53
|
}
|
54
|
+
.tab-hidden {
|
55
|
+
display: none;
|
56
|
+
}
|
57
|
+
pre {
|
58
|
+
overflow: auto;
|
59
|
+
}
|
60
|
+
pre code {
|
61
|
+
word-wrap: normal;
|
62
|
+
white-space: pre;
|
63
|
+
}
|
50
64
|
</style>
|
51
65
|
</head>
|
52
66
|
<body data-spy="scroll" data-target=".table-of-contents">
|
@@ -21,14 +21,68 @@ def format_validators(validators)
|
|
21
21
|
end
|
22
22
|
%>
|
23
23
|
|
24
|
-
<% def
|
24
|
+
<% def render_auth_body(name, info) %>
|
25
|
+
<h2 id="auth-<%= name %>"><%= name.to_s.humanize %></h2>
|
26
|
+
<hr>
|
27
|
+
|
28
|
+
<p><%= info[:description] %></p>
|
29
|
+
|
30
|
+
<% if name == :token %>
|
31
|
+
<dl>
|
32
|
+
<dt>HTTP header:</dt>
|
33
|
+
<dd><%= info[:http_header] %></dd>
|
34
|
+
<dt>Query parameter:</dt>
|
35
|
+
<dd><%= info[:query_parameter] %></dd>
|
36
|
+
</dl>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<% if info[:resources] %>
|
40
|
+
<h2>Resources</h2>
|
41
|
+
<% sort_hash(info[:resources]).each do |resource, desc| %>
|
42
|
+
<% render_resource_body(resource.to_s, desc, 'auth') %>
|
43
|
+
<% end %>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
<% baseid = "auth-#{name}" %>
|
47
|
+
<div id="<%= baseid %>-tabbar"></div>
|
48
|
+
|
49
|
+
<div id="<%= baseid %>-examples">
|
50
|
+
<% HaveAPI::ClientExample.clients.each_with_index do |client, i| %>
|
51
|
+
<div id="<%= "#{baseid}-#{i}" %>">
|
52
|
+
<% render_client_auth(client, name, info) %>
|
53
|
+
</div>
|
54
|
+
<% end %>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<script type="text/javascript">
|
58
|
+
nojsTabs({
|
59
|
+
tabs: document.getElementById('<%= "#{baseid}-examples" %>'),
|
60
|
+
titleSelector: 'h4',
|
61
|
+
tabBar: document.getElementById('<%= "#{baseid}-tabbar" %>'),
|
62
|
+
hiddenClass: 'tab-hidden',
|
63
|
+
activeClass: 'active',
|
64
|
+
createElement: function (el) {
|
65
|
+
if (el.tagName == 'UL')
|
66
|
+
el.classList.add('nav', 'nav-tabs');
|
67
|
+
|
68
|
+
else if (el.tagName == 'LI')
|
69
|
+
el.setAttribute('role', 'presentation');
|
70
|
+
}
|
71
|
+
});
|
72
|
+
</script>
|
73
|
+
<% end %>
|
74
|
+
|
75
|
+
<% def render_resource_body(resource, info, path = [], prefix='root', name=nil) %>
|
25
76
|
<% name ||= resource.humanize %>
|
77
|
+
<% resource_path = path.clone << resource %>
|
78
|
+
<% resource_info = info %>
|
26
79
|
<h2 class="resource" id="<%= "#{prefix}-#{resource}" %>"><%= resource.humanize %></h2>
|
80
|
+
<hr>
|
27
81
|
<div class="resource-body">
|
28
82
|
<p><%= info[:description] %></p>
|
29
83
|
|
30
84
|
<div class="actions">
|
31
|
-
<% info[:actions].each do |action, info| %>
|
85
|
+
<% sort_hash(info[:actions]).each do |action, info| %>
|
32
86
|
<h3 id="<%= "#{prefix}-#{resource}-#{action}" %>"><%= name %> # <%= action.capitalize %></h3>
|
33
87
|
<div class="action">
|
34
88
|
<dl>
|
@@ -40,6 +94,8 @@ end
|
|
40
94
|
<dd><%= info[:auth] ? 'yes' : 'no' %></dd>
|
41
95
|
<dt>Aliases:</dt>
|
42
96
|
<dd><%= info[:aliases].join(', ') %></dd>
|
97
|
+
<dt>Blocking:</dt>
|
98
|
+
<dd><%= info[:blocking] ? 'yes' : 'no' %></dd>
|
43
99
|
</dl>
|
44
100
|
|
45
101
|
<h4>Input parameters</h4>
|
@@ -54,7 +110,7 @@ end
|
|
54
110
|
<dd><%= info[:input][:namespace] %></dd>
|
55
111
|
</dl>
|
56
112
|
|
57
|
-
<table class="table table-striped table-hover">
|
113
|
+
<table class="table table-striped table-hover table-bordered">
|
58
114
|
<tr>
|
59
115
|
<th>Label</th>
|
60
116
|
<th>Name</th>
|
@@ -91,7 +147,7 @@ end
|
|
91
147
|
<dd><%= info[:output][:namespace] %></dd>
|
92
148
|
</dl>
|
93
149
|
|
94
|
-
<table class="table table-striped table-hover">
|
150
|
+
<table class="table table-striped table-hover table-bordered">
|
95
151
|
<tr>
|
96
152
|
<th>Label</th>
|
97
153
|
<th>Name</th>
|
@@ -117,15 +173,47 @@ end
|
|
117
173
|
|
118
174
|
<% unless info[:examples].empty? %>
|
119
175
|
<h4>Examples</h4>
|
120
|
-
<% info[:examples].
|
121
|
-
<h5><%= example[:
|
176
|
+
<% info[:examples].each_with_index do |example, i| %>
|
177
|
+
<h5><%= example[:title].empty? ? "Example ##{i}" : example[:title] %></h5>
|
122
178
|
<p><%= example[:comment] %></p>
|
123
179
|
|
124
|
-
|
125
|
-
|
180
|
+
<% baseid = "example-#{resource_path.join('.')}-#{action}-#{i}" %>
|
181
|
+
<%# placeholder for tabs %>
|
182
|
+
<div id="<%= "#{baseid}-tabbar" %>"></div>
|
183
|
+
|
184
|
+
<div id="<%= "#{baseid}-examples" %>">
|
185
|
+
<% HaveAPI::ClientExample.clients.each_with_index do |client, j| %>
|
186
|
+
<div id="<%= "#{baseid}-#{j}" %>">
|
187
|
+
<%
|
188
|
+
render_client_example(
|
189
|
+
client,
|
190
|
+
resource_path,
|
191
|
+
resource_info,
|
192
|
+
action,
|
193
|
+
info,
|
194
|
+
example
|
195
|
+
)
|
196
|
+
%>
|
197
|
+
</div>
|
198
|
+
<% end %>
|
199
|
+
</div>
|
200
|
+
|
201
|
+
<script type="text/javascript">
|
202
|
+
nojsTabs({
|
203
|
+
tabs: document.getElementById('<%= "#{baseid}-examples" %>'),
|
204
|
+
titleSelector: 'h6',
|
205
|
+
tabBar: document.getElementById('<%= "#{baseid}-tabbar" %>'),
|
206
|
+
hiddenClass: 'tab-hidden',
|
207
|
+
activeClass: 'active',
|
208
|
+
createElement: function (el) {
|
209
|
+
if (el.tagName == 'UL')
|
210
|
+
el.classList.add('nav', 'nav-tabs');
|
126
211
|
|
127
|
-
|
128
|
-
|
212
|
+
else if (el.tagName == 'LI')
|
213
|
+
el.setAttribute('role', 'presentation');
|
214
|
+
}
|
215
|
+
});
|
216
|
+
</script>
|
129
217
|
<% end %>
|
130
218
|
<% end %>
|
131
219
|
|
@@ -134,24 +222,110 @@ end
|
|
134
222
|
</div>
|
135
223
|
|
136
224
|
<% unless info[:resources].empty? %>
|
137
|
-
<% info[:resources].each do |r, i| %>
|
138
|
-
<% render_resource_body(r, i, "#{prefix}-#{resource}", "#{name}.#{r.humanize}") %>
|
225
|
+
<% sort_hash(info[:resources]).each do |r, i| %>
|
226
|
+
<% render_resource_body(r, i, resource_path, "#{prefix}-#{resource}", "#{name}.#{r.humanize}") %>
|
139
227
|
<% end %>
|
140
228
|
<% end %>
|
141
229
|
|
142
230
|
</div> <!-- resource -->
|
143
231
|
<% end %>
|
144
232
|
|
233
|
+
<% def render_client_init(client) %>
|
234
|
+
<h4><%= client.label %></h4>
|
235
|
+
<pre><code class="<%= client.code %>"><%= client.init(host, base_url, api_version) %></code></pre>
|
236
|
+
<% end %>
|
237
|
+
|
238
|
+
<% def render_client_auth(client, method, desc) %>
|
239
|
+
<h4><%= client.label %></h4>
|
240
|
+
<pre><code class="<%= client.code %>"><%= client.auth(host, base_url, api_version, method, desc) %></code></pre>
|
241
|
+
<% end %>
|
242
|
+
|
243
|
+
<% def render_client_example(client, r_name, resource, a_name, action, example) %>
|
244
|
+
<h6><%= client.label %></h6>
|
245
|
+
<% sample = client.new(host, base_url, api_version, r_name, resource, a_name, action) %>
|
246
|
+
<% if sample.respond_to?(:example) %>
|
247
|
+
<pre><code class="<%= client.code %>"><%= sample.example(example) %></code></pre>
|
248
|
+
|
249
|
+
<% else %>
|
250
|
+
<h6>Request</h6>
|
251
|
+
<pre><code class="<%= client.code %>"><%= sample.request(example) %></code></pre>
|
252
|
+
<h6>Response</h6>
|
253
|
+
<pre><code class="<%= client.code %>"><%= sample.response(example) %></code></pre>
|
254
|
+
<% end %>
|
255
|
+
<% end %>
|
256
|
+
|
257
|
+
|
145
258
|
<h1 id="api">API v<%= @v %></h1>
|
259
|
+
|
260
|
+
<ol class="breadcrumb">
|
261
|
+
<li><a href="<%= root %>"><%= host %></a></li>
|
262
|
+
<li class="active">v<%= @v %></li>
|
263
|
+
</ol>
|
264
|
+
|
146
265
|
<p>
|
147
266
|
This page contains a list of resources available in API v<%= @v %>, their actions,
|
148
267
|
description, parameters and example usage.
|
149
268
|
</p>
|
150
269
|
|
270
|
+
<p>
|
271
|
+
This API is based on the <a href="https://github.com/vpsfreecz/haveapi">HaveAPI</a> framework.
|
272
|
+
You can access it using existing clients:
|
273
|
+
</p>
|
274
|
+
|
275
|
+
<ul>
|
276
|
+
<li><a href="https://github.com/vpsfreecz/haveapi-client" target="_blank">Ruby library and CLI</a></li>
|
277
|
+
<li><a href="https://github.com/vpsfreecz/haveapi-client-js" target="_blank">JavaScript</a></li>
|
278
|
+
<li><a href="https://github.com/vpsfreecz/haveapi-client-php" target="_blank">PHP</a></li>
|
279
|
+
<li>
|
280
|
+
<a href="https://github.com/vpsfreecz/haveapi-webui" target="_blank">Generic web interface</a>
|
281
|
+
(<a href="https://webui.haveapi.org/v<%= version %>/#<%= escape(base_url) %>" target="_blank">connect to this API</a>)
|
282
|
+
</li>
|
283
|
+
<li><a href="https://github.com/vpsfreecz/haveapi-fs" target="_blank">FUSE-based file system</a></li>
|
284
|
+
</ul>
|
285
|
+
|
286
|
+
<p>
|
287
|
+
The code examples found on this page are for HaveAPI v<%= version %>, so be sure
|
288
|
+
to use clients of the same version.
|
289
|
+
</p>
|
290
|
+
|
291
|
+
<h2>Initialization</h2>
|
292
|
+
|
293
|
+
<div id="init-tabbar"></div>
|
294
|
+
|
295
|
+
<div id="init-examples">
|
296
|
+
<% HaveAPI::ClientExample.clients.each_with_index do |client, i| %>
|
297
|
+
<div id="<%= "init-#{i}" %>">
|
298
|
+
<% render_client_init(client) %>
|
299
|
+
</div>
|
300
|
+
<% end %>
|
301
|
+
</div>
|
302
|
+
|
303
|
+
<script type="text/javascript">
|
304
|
+
nojsTabs({
|
305
|
+
tabs: document.getElementById('init-examples'),
|
306
|
+
titleSelector: 'h4',
|
307
|
+
tabBar: document.getElementById('init-tabbar'),
|
308
|
+
hiddenClass: 'tab-hidden',
|
309
|
+
activeClass: 'active',
|
310
|
+
createElement: function (el) {
|
311
|
+
if (el.tagName == 'UL')
|
312
|
+
el.classList.add('nav', 'nav-tabs');
|
313
|
+
|
314
|
+
else if (el.tagName == 'LI')
|
315
|
+
el.setAttribute('role', 'presentation');
|
316
|
+
}
|
317
|
+
});
|
318
|
+
</script>
|
319
|
+
|
320
|
+
<h1 id="auth">Authentication methods</h1>
|
321
|
+
<% @help[:authentication].each do |name, info| %>
|
322
|
+
<% render_auth_body(name, info) %>
|
323
|
+
<% end %>
|
324
|
+
|
151
325
|
<h1 id="resources">Resources</h1>
|
152
326
|
<p>Follows a list of all resources in this API and their actions.</p>
|
153
327
|
|
154
|
-
<% @help[:resources].each do |resource, info| %>
|
328
|
+
<% sort_hash(@help[:resources]).each do |resource, info| %>
|
155
329
|
<% render_resource_body(resource, info) %>
|
156
330
|
<% end %>
|
157
331
|
</div>
|