apipie-rails 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +4 -3
- data/.github/workflows/rubocop-challenger.yml +1 -3
- data/.github/workflows/rubocop.yml +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +2 -3
- data/README.md +2088 -0
- data/apipie-rails.gemspec +7 -1
- data/app/views/apipie/apipies/_method_detail.erb +2 -0
- data/app/views/apipie/apipies/_params.html.erb +1 -0
- data/app/views/apipie/apipies/_params_plain.html.erb +1 -0
- data/config/locales/en.yml +1 -0
- data/config/locales/ko.yml +1 -0
- data/lib/apipie/application.rb +1 -1
- data/lib/apipie/dsl_definition.rb +3 -3
- data/lib/apipie/extractor/writer.rb +1 -1
- data/lib/apipie/generator/swagger/method_description/response_service.rb +14 -1
- data/lib/apipie/param_description.rb +1 -1
- data/lib/apipie/response_description.rb +34 -9
- data/lib/apipie/response_description_adapter.rb +1 -1
- data/lib/apipie/routes_formatter.rb +1 -1
- data/lib/apipie/version.rb +1 -1
- data/rel-eng/gem_release.ipynb +5 -5
- data/spec/controllers/users_controller_spec.rb +1 -1
- data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +1 -1
- data/spec/dummy/app/controllers/pets_controller.rb +1 -1
- data/spec/dummy/app/controllers/twitter_example_controller.rb +3 -3
- data/spec/lib/apipie/apipies_controller_spec.rb +1 -1
- data/spec/lib/apipie/file_handler_spec.rb +1 -1
- data/spec/lib/apipie/generator/swagger/method_description/response_service_spec.rb +62 -0
- data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +2 -2
- data/spec/lib/apipie/param_description_spec.rb +1 -1
- data/spec/lib/apipie/response_description/response_object_spec.rb +22 -0
- data/spec/lib/apipie/response_description_spec.rb +56 -0
- data/spec/lib/swagger/swagger_dsl_spec.rb +1 -1
- metadata +12 -6
- data/README.rst +0 -1968
data/README.md
ADDED
@@ -0,0 +1,2088 @@
|
|
1
|
+
# API Documentation Tool
|
2
|
+
|
3
|
+
[![image](https://github.com/Apipie/apipie-rails/actions/workflows/build.yml/badge.svg)](https://github.com/Apipie/apipie-rails/actions/workflows/build.yml)
|
4
|
+
[![image](https://codeclimate.com/github/Apipie/apipie-rails.svg)](https://codeclimate.com/github/Apipie/apipie-rails)
|
5
|
+
[![Join the chat at https://gitter.im/Apipie/apipie-rails](https://badges.gitter.im/Apipie/apipie-rails.svg)](https://gitter.im/Apipie/apipie-rails?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
6
|
+
[![Latest release](https://img.shields.io/gem/v/apipie-rails.svg)](https://rubygems.org/gems/apipie-rails)
|
7
|
+
|
8
|
+
Apipie-rails is a DSL and Rails engine for documenting your RESTful API.
|
9
|
+
Instead of traditional use of `#comments`, Apipie lets you describe the
|
10
|
+
code, through the code. This brings advantages like:
|
11
|
+
|
12
|
+
- No need to learn yet another syntax, you already know Ruby, right?
|
13
|
+
- Possibility of reusing the docs for other purposes (such as
|
14
|
+
validation)
|
15
|
+
- Easier to extend and maintain (no string parsing involved)
|
16
|
+
- Possibility of reusing other sources for documentation purposes
|
17
|
+
(such as routes etc.)
|
18
|
+
|
19
|
+
The documentation is available from within your app (by default under
|
20
|
+
the `/apipie` path.) In development mode, you can see the changes as you
|
21
|
+
go. It\'s markup language agnostic, and even provides an API for reusing
|
22
|
+
the documentation data in JSON.
|
23
|
+
|
24
|
+
## Getting started
|
25
|
+
|
26
|
+
The easiest way to get Apipie up and running with your app is:
|
27
|
+
|
28
|
+
``` sh
|
29
|
+
echo "gem 'apipie-rails'" >> Gemfile
|
30
|
+
bundle install
|
31
|
+
rails g apipie:install
|
32
|
+
```
|
33
|
+
|
34
|
+
Now you can start documenting your resources and actions (see [DSL
|
35
|
+
Reference](#dsl-reference) for more info):
|
36
|
+
|
37
|
+
``` ruby
|
38
|
+
api :GET, '/users/:id'
|
39
|
+
param :id, :number, desc: 'id of the requested user'
|
40
|
+
def show
|
41
|
+
# ...
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
Run your application and see the result at
|
46
|
+
`http://localhost:3000/apipie`. For further processing, you can use
|
47
|
+
`http://localhost:3000/apipie.json`.
|
48
|
+
|
49
|
+
For a more comprehensive getting started guide, see [this
|
50
|
+
demo](https://github.com/Apipie/apipie-demo), which includes features
|
51
|
+
such as generating documentation from tests, recording examples etc.
|
52
|
+
|
53
|
+
## Screenshots
|
54
|
+
|
55
|
+
![image](https://github.com/Apipie/apipie-rails/blob/master/images/screenshot-1.png)
|
56
|
+
|
57
|
+
![image](https://github.com/Apipie/apipie-rails/blob/master/images/screenshot-2.png)
|
58
|
+
|
59
|
+
## Authors
|
60
|
+
|
61
|
+
[Pajk](https://github.com/Pajk) and [iNecas](https://github.com/iNecas)
|
62
|
+
|
63
|
+
## Contributors
|
64
|
+
|
65
|
+
See [Contributors
|
66
|
+
page](https://github.com/Apipie/apipie-rails/graphs/contributors).
|
67
|
+
Special thanks to all of them!
|
68
|
+
|
69
|
+
## License
|
70
|
+
|
71
|
+
Apipie-rails is released under the [MIT
|
72
|
+
License](https://opensource.org/licenses/MIT)
|
73
|
+
|
74
|
+
## Table Of Contents
|
75
|
+
|
76
|
+
- [API Documentation Tool](#api-documentation-tool)
|
77
|
+
- [Getting started](#getting-started)
|
78
|
+
- [Screenshots](#screenshots)
|
79
|
+
- [Authors](#authors)
|
80
|
+
- [Contributors](#contributors)
|
81
|
+
- [License](#license)
|
82
|
+
- [Documentation](#documentation)
|
83
|
+
- [DSL Reference](#dsl-reference)
|
84
|
+
- [Resource Description](#resource-description)
|
85
|
+
- [Method Description](#method-description)
|
86
|
+
- [Parameter Description](#parameter-description)
|
87
|
+
- [DRY with param_group](#dry-with-param_group)
|
88
|
+
- [Action Aware params](#action-aware-params)
|
89
|
+
- [Response Description](#response-description)
|
90
|
+
- [Concerns](#concerns)
|
91
|
+
- [Response validation](#response-validation)
|
92
|
+
- [Configuration Reference](#configuration-reference)
|
93
|
+
- [Rails Routes Integration](#rails-routes-integration)
|
94
|
+
- [Processing](#processing)
|
95
|
+
- [Validators](#validators)
|
96
|
+
- [TypeValidator](#typevalidator)
|
97
|
+
- [RegexpValidator](#regexpvalidator)
|
98
|
+
- [EnumValidator](#enumvalidator)
|
99
|
+
- [ProcValidator](#procvalidator)
|
100
|
+
- [HashValidator](#hashvalidator)
|
101
|
+
- [NilValidator](#nilvalidator)
|
102
|
+
- [NumberValidator](#numbervalidator)
|
103
|
+
- [DecimalValidator](#decimalvalidator)
|
104
|
+
- [ArrayValidator](#arrayvalidator)
|
105
|
+
- [NestedValidator](#nestedvalidator)
|
106
|
+
- [Adding custom validator](#adding-custom-validator)
|
107
|
+
- [Versioning](#versioning)
|
108
|
+
- [Markup](#markup)
|
109
|
+
- [Localization](#localization)
|
110
|
+
- [Modifying Views](#modifying-views)
|
111
|
+
- [Static files](#static-files)
|
112
|
+
- [Static Swagger (OpenAPI 2.0) files](#static-swagger-openapi-20-files)
|
113
|
+
- [Specifying default values for parameters](#specifying-default-values-for-parameters)
|
114
|
+
- [Generated Warnings](#generated-warnings)
|
115
|
+
- [Swagger-Specific Configuration Parameters](#swagger-specific-configuration-parameters)
|
116
|
+
- [Known limitations of the current implementation](#known-limitations-of-the-current-implementation)
|
117
|
+
- [Dynamic Swagger generation](#dynamic-swagger-generation)
|
118
|
+
- [JSON checksums](#json-checksums)
|
119
|
+
- [Tests Integration](#tests-integration)
|
120
|
+
- [Documentation Bootstrapping](#documentation-bootstrapping)
|
121
|
+
- [Examples Recording](#examples-recording)
|
122
|
+
- [Caveats](#caveats)
|
123
|
+
- [Bindings Generator](#bindings-generator)
|
124
|
+
- [Contributing](#contributing)
|
125
|
+
- [Disqus Integration](#disqus-integration)
|
126
|
+
- [External References](#external-references)
|
127
|
+
|
128
|
+
# DSL Reference
|
129
|
+
|
130
|
+
## Resource Description
|
131
|
+
|
132
|
+
You can describe a resource on the controller level. The description is
|
133
|
+
introduced by calling `resource_description do ... end`.
|
134
|
+
|
135
|
+
Inheritance is supported, so you can specify common params for group of
|
136
|
+
controllers in their parent class.
|
137
|
+
|
138
|
+
The following keywords are available (all are optional):
|
139
|
+
|
140
|
+
`resource_id`
|
141
|
+
|
142
|
+
How the resource will be referenced in Apipie (paths, `see` command etc.); by default `controller_name.downcase` is used.
|
143
|
+
|
144
|
+
`name`
|
145
|
+
|
146
|
+
Human readable name of resource. By default `class.name.humanize` is
|
147
|
+
used.
|
148
|
+
|
149
|
+
- Can be specified as a proc, which will receive the controller
|
150
|
+
class as an argument.
|
151
|
+
- Can be a symbol, which will be sent to the controller class to
|
152
|
+
get the name.
|
153
|
+
- Can be a string, which will be used as is.
|
154
|
+
|
155
|
+
`short` (also `short_description`)
|
156
|
+
|
157
|
+
Short description of the resource (it\'s shown on both the list of resources, and resource details)
|
158
|
+
|
159
|
+
`desc` (also description and full_description)
|
160
|
+
|
161
|
+
Full description of the resource (shown only in resource details)
|
162
|
+
|
163
|
+
`param`
|
164
|
+
|
165
|
+
Common params for all methods defined in controller/child controllers.
|
166
|
+
|
167
|
+
`returns`
|
168
|
+
|
169
|
+
Common responses for all methods defined in controller/child controllers.
|
170
|
+
|
171
|
+
`api_base_url`
|
172
|
+
|
173
|
+
What URL is the resource available under.
|
174
|
+
|
175
|
+
`api_versions` (also api_version)
|
176
|
+
|
177
|
+
What versions does the controller define the resource. (See [Versioning](#versioning) for details.)
|
178
|
+
|
179
|
+
`formats`
|
180
|
+
|
181
|
+
Request / response formats.
|
182
|
+
|
183
|
+
`error`
|
184
|
+
|
185
|
+
Describe every possible error that can happen when calling all
|
186
|
+
methods defined in controller. HTTP response code and description
|
187
|
+
can be provided.
|
188
|
+
|
189
|
+
`app_info`
|
190
|
+
|
191
|
+
In case of versioning, this sets app info description on a per_version basis.
|
192
|
+
|
193
|
+
`meta`
|
194
|
+
|
195
|
+
Hash or array with custom metadata.
|
196
|
+
|
197
|
+
`deprecated`
|
198
|
+
|
199
|
+
Boolean value indicating if the resource is marked as deprecated. (Default `false`)
|
200
|
+
|
201
|
+
### Example:
|
202
|
+
|
203
|
+
``` ruby
|
204
|
+
resource_description do
|
205
|
+
short 'Site members'
|
206
|
+
formats ['json']
|
207
|
+
param :id, Integer, :desc => "User ID", :required => false
|
208
|
+
param :resource_param, Hash, :desc => 'Param description for all methods' do
|
209
|
+
param :ausername, String, :desc => "Username for login", :required => true
|
210
|
+
param :apassword, String, :desc => "Password for login", :required => true
|
211
|
+
end
|
212
|
+
api_version "development"
|
213
|
+
error 404, "Missing"
|
214
|
+
error 500, "Server crashed for some <%= reason %>", :meta => {:anything => "you can think of"}
|
215
|
+
error :unprocessable_entity, "Could not save the entity."
|
216
|
+
returns :code => 403 do
|
217
|
+
property :reason, String, :desc => "Why this was forbidden"
|
218
|
+
end
|
219
|
+
meta :author => {:name => 'John', :surname => 'Doe'}
|
220
|
+
deprecated false
|
221
|
+
description <<-EOS
|
222
|
+
== Long description
|
223
|
+
Example resource for rest api documentation
|
224
|
+
These can now be accessed in <tt>shared/header</tt> with:
|
225
|
+
Headline: <%= headline %>
|
226
|
+
First name: <%= person.first_name %>
|
227
|
+
|
228
|
+
If you need to find out whether a certain local variable has been
|
229
|
+
assigned a value in a particular render call, you need to use the
|
230
|
+
following pattern:
|
231
|
+
|
232
|
+
<% if local_assigns.has_key? :headline %>
|
233
|
+
Headline: <%= headline %>
|
234
|
+
<% end %>
|
235
|
+
|
236
|
+
Testing using <tt>defined? headline</tt> will not work. This is an
|
237
|
+
implementation restriction.
|
238
|
+
|
239
|
+
=== Template caching
|
240
|
+
|
241
|
+
By default, Rails will compile each template to a method in order
|
242
|
+
to render it. When you alter a template, Rails will check the
|
243
|
+
file's modification time and recompile it in development mode.
|
244
|
+
EOS
|
245
|
+
end
|
246
|
+
```
|
247
|
+
|
248
|
+
## Method Description
|
249
|
+
|
250
|
+
Then describe methods available to your API.
|
251
|
+
|
252
|
+
`api`
|
253
|
+
|
254
|
+
Describe how this method is exposed, and provide a short
|
255
|
+
description. The first parameter is HTTP method (one of
|
256
|
+
:GET/:POST/:PUT/:DELETE). The second parameter is the relative URL
|
257
|
+
path which is mapped to this method. The last parameter is the
|
258
|
+
methods short description. You can use this +api+ method more than
|
259
|
+
once per method. It could be useful when there are more routes
|
260
|
+
mapped to it.
|
261
|
+
|
262
|
+
When providing just one argument (description), or no argument at
|
263
|
+
all, the paths will be loaded from the routes.rb file.
|
264
|
+
|
265
|
+
`api!`
|
266
|
+
|
267
|
+
Provide a short description and additional option. The last
|
268
|
+
parameter is the methods short description. The paths will be loaded
|
269
|
+
from routes.rb file. See [Rails Routes
|
270
|
+
Integration](#rails-routes-integration) for more details.
|
271
|
+
|
272
|
+
`api_versions` (also api_version)
|
273
|
+
|
274
|
+
What version(s) does the action belong to. (See
|
275
|
+
[Versioning](#versioning) for details.)
|
276
|
+
|
277
|
+
`param`
|
278
|
+
|
279
|
+
Look at [Parameter description](#parameter-description) section for
|
280
|
+
details.
|
281
|
+
|
282
|
+
`returns`
|
283
|
+
|
284
|
+
Look at [Response description](#response-description) section for
|
285
|
+
details.
|
286
|
+
|
287
|
+
`tags`
|
288
|
+
|
289
|
+
Adds tags for grouping operations together in Swagger outputs. See
|
290
|
+
[swagger](#Swagger) for more details. You can also provide tags in
|
291
|
+
the [Resource Description](#resource-description) block so that they
|
292
|
+
are automatically prepended to all action tags in the controller.
|
293
|
+
|
294
|
+
`formats`
|
295
|
+
|
296
|
+
Method level request / response formats.
|
297
|
+
|
298
|
+
`error`
|
299
|
+
|
300
|
+
Describe each possible error that can happen while calling this
|
301
|
+
method. HTTP response code and description can be provided.
|
302
|
+
|
303
|
+
`description`
|
304
|
+
|
305
|
+
Full method description, which will be converted into HTML by the
|
306
|
+
chosen markup language processor.
|
307
|
+
|
308
|
+
`example`
|
309
|
+
|
310
|
+
Provide an example of the server response; whole communication or
|
311
|
+
response type. It will be formatted as code.
|
312
|
+
|
313
|
+
`see`
|
314
|
+
|
315
|
+
Provide reference to another method, this has to be a string with
|
316
|
+
controller_name#method_name.
|
317
|
+
|
318
|
+
`meta`
|
319
|
+
|
320
|
+
Hash or array with custom metadata.
|
321
|
+
|
322
|
+
`show`
|
323
|
+
|
324
|
+
Resource is hidden from documentation when set to false (true by
|
325
|
+
default)
|
326
|
+
|
327
|
+
### Example:
|
328
|
+
|
329
|
+
``` ruby
|
330
|
+
# The simplest case: just load the paths from routes.rb
|
331
|
+
api!
|
332
|
+
def index
|
333
|
+
end
|
334
|
+
|
335
|
+
# More complex example
|
336
|
+
api :GET, "/users/:id", "Show user profile"
|
337
|
+
show false
|
338
|
+
error :code => 401, :desc => "Unauthorized"
|
339
|
+
error :code => 404, :desc => "Not Found", :meta => {:anything => "you can think of"}
|
340
|
+
param :session, String, :desc => "user is logged in", :required => true
|
341
|
+
param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
|
342
|
+
param :array_param, [100, "one", "two", 1, 2], :desc => "array validator"
|
343
|
+
param :boolean_param, [true, false], :desc => "array validator with boolean"
|
344
|
+
param :proc_param, lambda { |val|
|
345
|
+
val == "param value" ? true : "The only good value is 'param value'."
|
346
|
+
}, :desc => "proc validator"
|
347
|
+
param :param_with_metadata, String, :desc => "", :meta => [:your, :custom, :metadata]
|
348
|
+
returns :code => 200, :desc => "a successful response" do
|
349
|
+
property :value1, String, :desc => "A string value"
|
350
|
+
property :value2, Integer, :desc => "An integer value"
|
351
|
+
property :value3, Hash, :desc => "An object" do
|
352
|
+
property :enum1, ['v1', 'v2'], :desc => "One of 2 possible string values"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
tags %w[profiles logins]
|
356
|
+
tags 'more', 'related', 'resources'
|
357
|
+
description "method description"
|
358
|
+
formats ['json', 'jsonp', 'xml']
|
359
|
+
meta :message => "Some very important info"
|
360
|
+
example " 'user': {...} "
|
361
|
+
see "users#showme", "link description"
|
362
|
+
see :link => "users#update", :desc => "another link description"
|
363
|
+
def show
|
364
|
+
#...
|
365
|
+
end
|
366
|
+
```
|
367
|
+
|
368
|
+
## Parameter Description
|
369
|
+
|
370
|
+
Use `param` to describe every possible parameter. You can use the Hash
|
371
|
+
validator in conjunction with a block given to the param method to
|
372
|
+
describe nested parameters.
|
373
|
+
|
374
|
+
`name`
|
375
|
+
|
376
|
+
The first argument is the parameter name as a symbol.
|
377
|
+
|
378
|
+
`validator`
|
379
|
+
|
380
|
+
Second parameter is the parameter validator, choose one from section
|
381
|
+
[Validators](#validators)
|
382
|
+
|
383
|
+
`desc`
|
384
|
+
|
385
|
+
Parameter description.
|
386
|
+
|
387
|
+
`required`
|
388
|
+
|
389
|
+
Set this true/false to make it required/optional. Default is
|
390
|
+
optional
|
391
|
+
|
392
|
+
`example`
|
393
|
+
|
394
|
+
Provide the example for this parameter.
|
395
|
+
|
396
|
+
`allow_nil`
|
397
|
+
|
398
|
+
Setting this to true means that `nil` can be passed.
|
399
|
+
|
400
|
+
`allow_blank`
|
401
|
+
|
402
|
+
Like `allow_nil`, but for blank values. `false`, `""`, `' '`, `nil`,
|
403
|
+
`[]`, and `{}` are all blank.
|
404
|
+
|
405
|
+
`as`
|
406
|
+
|
407
|
+
Used by the processing functionality to change the name of a key params.
|
408
|
+
|
409
|
+
`meta`
|
410
|
+
|
411
|
+
Hash or array with custom metadata.
|
412
|
+
|
413
|
+
`show`
|
414
|
+
|
415
|
+
Parameter is hidden from documentation when set to false (true by default)
|
416
|
+
|
417
|
+
`missing_message`
|
418
|
+
|
419
|
+
Specify the message to be returned if the parameter is missing as a
|
420
|
+
string or Proc. Defaults to `Missing parameter #{name}` if not
|
421
|
+
specified.
|
422
|
+
|
423
|
+
`only_in`
|
424
|
+
|
425
|
+
This can be set to `:request` or `:response`. Setting to `:response`
|
426
|
+
causes the param to be ignored when used as part of a request
|
427
|
+
description. Setting to `:request` causes this param to be ignored
|
428
|
+
when used as part of a response description. If `only_in` is not
|
429
|
+
specified, the param definition is used for both requests and
|
430
|
+
responses. (Note that the keyword `property` is similar to `param`,
|
431
|
+
but it has a `:only_in => :response` default).
|
432
|
+
|
433
|
+
### Example:
|
434
|
+
|
435
|
+
``` ruby
|
436
|
+
param :user, Hash, :desc => "User info" do
|
437
|
+
param :username, String, :desc => "Username for login", :required => true, :example => 'John'
|
438
|
+
param :password, String, :desc => "Password for login", :required => true, :example => '1234567'
|
439
|
+
param :membership, ["standard","premium"], :desc => "User membership"
|
440
|
+
param :admin_override, String, :desc => "Not shown in documentation", :show => false
|
441
|
+
param :ip_address, String, :desc => "IP address", :required => true, :missing_message => lambda { I18n.t("ip_address.required") }
|
442
|
+
end
|
443
|
+
def create
|
444
|
+
#...
|
445
|
+
end
|
446
|
+
```
|
447
|
+
|
448
|
+
`deprecated`
|
449
|
+
|
450
|
+
Indicates if the parameter is marked as deprecated.
|
451
|
+
|
452
|
+
### Example
|
453
|
+
|
454
|
+
``` ruby
|
455
|
+
param :pet_name, String, desc: "Name of pet", deprecated: true
|
456
|
+
param :pet_name, String, desc: "Name of pet", deprecated: 'Some deprecation info'
|
457
|
+
param :pet_name, String, desc: "Name of pet", deprecated: { in: "2.3", info: "Something", sunset: "3.0" }
|
458
|
+
def create
|
459
|
+
#...
|
460
|
+
end
|
461
|
+
```
|
462
|
+
|
463
|
+
## DRY with param_group
|
464
|
+
|
465
|
+
Often, params occur together in more actions. Typically, most of the
|
466
|
+
params for `create` and `update` actions are shared between them.
|
467
|
+
|
468
|
+
These params can be extracted with `def_param_group` and `param_group`
|
469
|
+
keywords.
|
470
|
+
|
471
|
+
The definition is looked up in the scope of the controller. If the group
|
472
|
+
is defined in a different controller, it might be referenced by
|
473
|
+
specifying the second argument.
|
474
|
+
|
475
|
+
### Example:
|
476
|
+
|
477
|
+
``` ruby
|
478
|
+
# v1/users_controller.rb
|
479
|
+
def_param_group :address do
|
480
|
+
param :street, String
|
481
|
+
param :number, Integer
|
482
|
+
param :zip, String
|
483
|
+
end
|
484
|
+
|
485
|
+
def_param_group :user do
|
486
|
+
param :user, Hash do
|
487
|
+
param :name, String, "Name of the user"
|
488
|
+
param_group :address
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
api :POST, "/users", "Create a user"
|
493
|
+
param_group :user
|
494
|
+
def create
|
495
|
+
# ...
|
496
|
+
end
|
497
|
+
|
498
|
+
api :PUT, "/users/:id", "Update a user"
|
499
|
+
param_group :user
|
500
|
+
def update
|
501
|
+
# ...
|
502
|
+
end
|
503
|
+
|
504
|
+
# v2/users_controller.rb
|
505
|
+
api :POST, "/users", "Create a user"
|
506
|
+
param_group :user, V1::UsersController
|
507
|
+
def create
|
508
|
+
# ...
|
509
|
+
end
|
510
|
+
```
|
511
|
+
|
512
|
+
## Action Aware params
|
513
|
+
|
514
|
+
In CRUD operations, this pattern occurs quite often - params that need
|
515
|
+
to be set are:
|
516
|
+
|
517
|
+
- for create action: `required => true` and `allow_nil => false`
|
518
|
+
- for update action: `required => false` and `allow_nil => false`
|
519
|
+
|
520
|
+
This makes it hard to share the param definitions across these actions.
|
521
|
+
Therefore, you can make the description a bit smarter by setting
|
522
|
+
`:action_aware => true`.
|
523
|
+
|
524
|
+
You can specify explicitly how the param group should be evaluated with
|
525
|
+
`:as` option (either :create or :update)
|
526
|
+
|
527
|
+
### Example
|
528
|
+
|
529
|
+
``` ruby
|
530
|
+
def_param_group :user do
|
531
|
+
param :user, Hash, :action_aware => true do
|
532
|
+
param :name, String, :required => true
|
533
|
+
param :description, String
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
api :POST, "/users", "Create a user"
|
538
|
+
param_group :user
|
539
|
+
def create
|
540
|
+
# ...
|
541
|
+
end
|
542
|
+
|
543
|
+
api :PUT, "/users/admin", "Create an admin"
|
544
|
+
param_group :user, :as => :create
|
545
|
+
def create_admin
|
546
|
+
# ...
|
547
|
+
end
|
548
|
+
|
549
|
+
api :PUT, "/users/:id", "Update a user"
|
550
|
+
param_group :user
|
551
|
+
def update
|
552
|
+
# ...
|
553
|
+
end
|
554
|
+
```
|
555
|
+
|
556
|
+
In this case, `user[name]` will be not be allowed nil for all actions
|
557
|
+
and required only for `create` and `create_admin`. Params with
|
558
|
+
`allow_nil` set explicitly don\'t have this value changed.
|
559
|
+
|
560
|
+
Action awareness is inherited from ancestors (in terms of nested
|
561
|
+
params).
|
562
|
+
|
563
|
+
## Response Description
|
564
|
+
|
565
|
+
The response from an API call can be documented by adding a `returns`
|
566
|
+
statement to the method description. This is especially useful when
|
567
|
+
using Apipie to auto-generate a machine-readable Swagger definition of
|
568
|
+
your API (see the [swagger](#Swagger) section for more details).
|
569
|
+
|
570
|
+
A `returns` statement has several possible formats:
|
571
|
+
|
572
|
+
``` ruby
|
573
|
+
# format #1: reference to a param-group
|
574
|
+
returns <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
|
575
|
+
|
576
|
+
# format #2: inline response definition
|
577
|
+
returns :code => <number>|<http-response-code-symbol> [, :desc => <human-readable description>] do
|
578
|
+
# property ...
|
579
|
+
# property ...
|
580
|
+
# param_group ...
|
581
|
+
end
|
582
|
+
|
583
|
+
# format #3: describing an array-of-objects response
|
584
|
+
returns :array_of => <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
|
585
|
+
```
|
586
|
+
|
587
|
+
If the `:code` argument is omitted, `200` is used.
|
588
|
+
|
589
|
+
### Example
|
590
|
+
|
591
|
+
``` ruby
|
592
|
+
# ------------------------------------------------
|
593
|
+
# Example of format #1 (reference to param-group):
|
594
|
+
# ------------------------------------------------
|
595
|
+
# the param_group :pet is defined here to describe the output returned by the method below.
|
596
|
+
def_param_group :pet do
|
597
|
+
property :pet_name, String, :desc => "Name of pet"
|
598
|
+
property :animal_type, ['dog','cat','iguana','kangaroo'], :desc => "Type of pet"
|
599
|
+
end
|
600
|
+
|
601
|
+
api :GET, "/pets/:id", "Get a pet record"
|
602
|
+
returns :pet, :desc => "The pet"
|
603
|
+
def show_detailed
|
604
|
+
render JSON({:pet_name => "Skippie", :animal_type => "kangaroo"})
|
605
|
+
end
|
606
|
+
|
607
|
+
# ------------------------------------------------
|
608
|
+
# Example of format #2 (inline):
|
609
|
+
# ------------------------------------------------
|
610
|
+
api :GET, "/pets/:id/with-extra-details", "Get a detailed pet record"
|
611
|
+
returns :code => 200, :desc => "Detailed info about the pet" do
|
612
|
+
param_group :pet
|
613
|
+
property :num_legs, Integer, :desc => "How many legs the pet has"
|
614
|
+
end
|
615
|
+
def show
|
616
|
+
render JSON({:pet_name => "Barkie", :animal_type => "iguana", :legs => 4})
|
617
|
+
end
|
618
|
+
|
619
|
+
# ------------------------------------------------
|
620
|
+
# Example of format #3 (array response):
|
621
|
+
# ------------------------------------------------
|
622
|
+
api :GET, "/pets", "Get all pet records"
|
623
|
+
returns :array_of => :pet, :code => 200, :desc => "All pets"
|
624
|
+
def index
|
625
|
+
render JSON([ {:pet_name => "Skippie", :animal_type => "kangaroo"},
|
626
|
+
{:pet_name => "Woofie", :animal_type => "cat"} ])
|
627
|
+
end
|
628
|
+
```
|
629
|
+
|
630
|
+
Note the use of the `property` keyword rather than `param`. This is the
|
631
|
+
preferred mechanism for documenting response-only fields.
|
632
|
+
|
633
|
+
#### Specify response headers
|
634
|
+
|
635
|
+
We can specify the response headers using the `header` keyword within the `returns` block.
|
636
|
+
|
637
|
+
##### Example
|
638
|
+
```ruby
|
639
|
+
api :GET, "/pets/:id/with-extra-details", "Get a detailed pet record"
|
640
|
+
returns code: 200, desc: "Detailed info about the pet" do
|
641
|
+
param_group :pet
|
642
|
+
property :num_legs, Integer, :desc => "How many legs the pet has"
|
643
|
+
header 'Link', String, 'Relative links'
|
644
|
+
header 'Current-Page', Integer, 'The current page', required: true
|
645
|
+
end
|
646
|
+
|
647
|
+
def show
|
648
|
+
render JSON({ :pet_name => "Barkie", :animal_type => "iguana", :legs => 4 })
|
649
|
+
end
|
650
|
+
```
|
651
|
+
|
652
|
+
#### The Property keyword
|
653
|
+
|
654
|
+
`property` is very similar to `param` with the following differences:
|
655
|
+
|
656
|
+
- a `property` is `:only_in => :response` by default
|
657
|
+
- a `property` is `:required => :true` by default
|
658
|
+
- a `property` can be an `:array_of` objects
|
659
|
+
|
660
|
+
##### Example
|
661
|
+
|
662
|
+
``` ruby
|
663
|
+
property :example, :array_of => Hash do
|
664
|
+
property :number1, Integer
|
665
|
+
property :number2, Integer
|
666
|
+
end
|
667
|
+
```
|
668
|
+
|
669
|
+
#### Describing multiple return codes
|
670
|
+
|
671
|
+
To describe multiple possible return codes, the `:returns` keyword can
|
672
|
+
be repeated as many times as necessary (once for each return code). Each
|
673
|
+
one of the `:returns` entries can specify a different response format.
|
674
|
+
|
675
|
+
##### Example
|
676
|
+
|
677
|
+
``` ruby
|
678
|
+
api :GET, "/pets/:id/extra_info", "Get extra information about a pet"
|
679
|
+
returns :desc => "Found a pet" do
|
680
|
+
param_group :pet
|
681
|
+
property 'pet_history', Hash do
|
682
|
+
param_group :pet_history
|
683
|
+
end
|
684
|
+
end
|
685
|
+
returns :code => :unprocessable_entity, :desc => "Fleas were discovered on the pet" do
|
686
|
+
param_group :pet
|
687
|
+
property :num_fleas, Integer, :desc => "Number of fleas on this pet"
|
688
|
+
end
|
689
|
+
def show_extra_info
|
690
|
+
# ... implementation here
|
691
|
+
end
|
692
|
+
```
|
693
|
+
|
694
|
+
#### Reusing a param_group to describe inputs and outputs
|
695
|
+
|
696
|
+
In many cases (such as CRUD implementations), the output from certain
|
697
|
+
API calls is very similar - but not identical - to the inputs of the
|
698
|
+
same or other API calls.
|
699
|
+
|
700
|
+
If you already have a `:param_group` that defines the input to a
|
701
|
+
`create` or `update routine, it would be quite
|
702
|
+
frustrating to have to define a completely separate `:param_group` to
|
703
|
+
describe the output of the `show` routine.
|
704
|
+
|
705
|
+
To address such situations, it is possible to define a single
|
706
|
+
`:param_group` which combines `param` and `property` statements (as well
|
707
|
+
as `:only_in => :request` / `:only_in => :response`) to differentiate
|
708
|
+
between fields that are only expected in the request, only included in
|
709
|
+
the response, or common to both.
|
710
|
+
|
711
|
+
This is somewhat analogous to the way [Action Aware
|
712
|
+
params](#action-aware-params) work.
|
713
|
+
|
714
|
+
##### Example
|
715
|
+
|
716
|
+
``` ruby
|
717
|
+
def_param_group :user_record
|
718
|
+
param :name, String # this is commong to both the request and the response
|
719
|
+
param :force_update, [true, false], :only_in => :request # this does not show up in responses
|
720
|
+
property :last_login, String # this shows up only in the response
|
721
|
+
end
|
722
|
+
|
723
|
+
api :POST, "/users", "Create a user"
|
724
|
+
param_group :user_record # the :last_login field is not expected here, but :force_update is
|
725
|
+
def create
|
726
|
+
# ...
|
727
|
+
end
|
728
|
+
|
729
|
+
api :GET, "/users", "Create a user"
|
730
|
+
returns :array_of => :user_record # the :last_login field will be included in the response, but :force_update will not
|
731
|
+
def index
|
732
|
+
# ...
|
733
|
+
end
|
734
|
+
```
|
735
|
+
|
736
|
+
#### Embedded response descriptions
|
737
|
+
|
738
|
+
If the code creating JSON responses is encapsulated within dedicated
|
739
|
+
classes, it can be more convenient to place the response descriptions
|
740
|
+
outside of the controller and embed them within the response generator.
|
741
|
+
|
742
|
+
To support such use cases, Apipie allows any class to provide a
|
743
|
+
`describe_own_properties` class method which returns a
|
744
|
+
description of the properties such a class would expose. It is then
|
745
|
+
possible to specify that class in the `returns` statement
|
746
|
+
instead of a `param_group`.
|
747
|
+
|
748
|
+
The `describe_own_properties` method is expected to return
|
749
|
+
an array of `Apipie::prop` objects, each one describing a
|
750
|
+
single property.
|
751
|
+
|
752
|
+
##### Example
|
753
|
+
|
754
|
+
``` ruby
|
755
|
+
class Pet
|
756
|
+
# this method is automatically called by Apipie when Pet is specified as the returned object type
|
757
|
+
def self.describe_own_properties
|
758
|
+
[
|
759
|
+
Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
|
760
|
+
Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
|
761
|
+
Apipie::additional_properties(false) # this indicates that :pet_name and :animal_type are the only properties in the response
|
762
|
+
]
|
763
|
+
end
|
764
|
+
|
765
|
+
# this method w
|
766
|
+
def json
|
767
|
+
JSON({:pet_name => @name, :animal_type => @type })
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
|
772
|
+
class PetsController
|
773
|
+
api :GET, "/index", "Get all pets"
|
774
|
+
returns :array_of => Pet # Pet is a 'self-describing-class'
|
775
|
+
def index
|
776
|
+
# ...
|
777
|
+
end
|
778
|
+
end
|
779
|
+
```
|
780
|
+
|
781
|
+
A use case where this is very useful is when JSON generation is done
|
782
|
+
using a reflection mechanism or some other sort of declarative
|
783
|
+
mechanism.
|
784
|
+
|
785
|
+
The `Apipie::prop` function expects the following inputs:
|
786
|
+
|
787
|
+
``` ruby
|
788
|
+
Apipie::prop(<property-name>, <property-type>, <options-hash> [, <array of sub-properties>])
|
789
|
+
|
790
|
+
# property-name should be a symbol
|
791
|
+
#
|
792
|
+
# property-type can be any of the following strings:
|
793
|
+
# "integer": maps to a swagger "integer" with an "int32" format
|
794
|
+
# "long": maps to a swagger "integer" with an "int64" format
|
795
|
+
# "number": maps to a swagger "number"(no format specifier)
|
796
|
+
# "float": maps to a swagger "number" with a "float" format
|
797
|
+
# "double": maps to a swagger "number" with a "double" format
|
798
|
+
# "string": maps to a swagger "string" (no format specifier)
|
799
|
+
# "byte": maps to a swagger "string" with a "byte" format
|
800
|
+
# "binary": maps to a swagger "string" with a "binary" format
|
801
|
+
# "boolean": maps to a swagger "boolean" (no format specifier)
|
802
|
+
# "date": maps to a swagger "string" with a "date" format
|
803
|
+
# "dateTime": maps to a swagger "string" with a "date-time" format
|
804
|
+
# "password": maps to a swagger "string" with a "password" format
|
805
|
+
# "object": the property has sub-properties. include <array of sub-properties> in the call.
|
806
|
+
# (see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more information
|
807
|
+
# about the mapped swagger types)
|
808
|
+
#
|
809
|
+
# options-hash can include any of the options fields allowed in a :returns statement.
|
810
|
+
# additionally, it can include the ':is_array => true', in which case the property is understood to be
|
811
|
+
# an array of the described type.
|
812
|
+
```
|
813
|
+
|
814
|
+
To describe an embedded object:
|
815
|
+
|
816
|
+
``` ruby
|
817
|
+
#
|
818
|
+
# PetWithMeasurements is a self-describing class with an embedded object
|
819
|
+
#
|
820
|
+
class PetWithMeasurements
|
821
|
+
def self.describe_own_properties
|
822
|
+
[
|
823
|
+
Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
|
824
|
+
Apipie::prop('animal_type', 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
|
825
|
+
Apipie::prop(:pet_measurements, 'object', {}, [
|
826
|
+
Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
|
827
|
+
Apipie::prop(:height, 'number', {:description => "Height in inches" }),
|
828
|
+
Apipie::prop(:num_legs, 'number', {:description => "Number of legs", :required => false }),
|
829
|
+
Apipie::additional_properties(false)
|
830
|
+
])
|
831
|
+
]
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
#
|
836
|
+
# PetWithManyMeasurements is a self-describing class with an embedded array of objects
|
837
|
+
#
|
838
|
+
class PetWithManyMeasurements
|
839
|
+
def self.describe_own_properties
|
840
|
+
[
|
841
|
+
Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
|
842
|
+
Apipie::prop(:many_pet_measurements, 'object', {is_array: true}, [
|
843
|
+
Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
|
844
|
+
Apipie::prop(:height, 'number', {:description => "Height in inches" }),
|
845
|
+
])
|
846
|
+
]
|
847
|
+
end
|
848
|
+
end
|
849
|
+
```
|
850
|
+
|
851
|
+
## Concerns
|
852
|
+
|
853
|
+
Sometimes, the actions are not defined in the controller class directly
|
854
|
+
but included from a module instead. You can load the Apipie DSL into the
|
855
|
+
module by extending it with `Apipie::DSL::Concern`.
|
856
|
+
|
857
|
+
The module can be used in more controllers. Therefore there is a way to
|
858
|
+
substitute parts of the documentation in the module with controller
|
859
|
+
specific values. These substitutions can be stated explicitly with
|
860
|
+
`apipie_concern_subst(:key => "value")` (needs to be called before the
|
861
|
+
module is included to take effect). The substitutions are performed in
|
862
|
+
the paths and descriptions of APIs and names and descriptions of params.
|
863
|
+
|
864
|
+
There are some default substitutions available:
|
865
|
+
|
866
|
+
`:controller_path`
|
867
|
+
|
868
|
+
value of `controller.controller_path`, e.g. `api/users` for
|
869
|
+
`Api::UsersController`. Only if not using the `api!` keyword.
|
870
|
+
|
871
|
+
`:resource_id`
|
872
|
+
|
873
|
+
Apipie identifier of the resource, e.g. `users` for
|
874
|
+
`Api::UsersController` or set by `resource_id`
|
875
|
+
|
876
|
+
### Example
|
877
|
+
|
878
|
+
``` ruby
|
879
|
+
# users_module.rb
|
880
|
+
module UsersModule
|
881
|
+
extend Apipie::DSL::Concern
|
882
|
+
|
883
|
+
api :GET, '/:controller_path', 'List :resource_id'
|
884
|
+
def index
|
885
|
+
# ...
|
886
|
+
end
|
887
|
+
|
888
|
+
api! 'Show a :resource'
|
889
|
+
def show
|
890
|
+
# ...
|
891
|
+
end
|
892
|
+
|
893
|
+
api :POST, '/:resource_id', "Create a :resource"
|
894
|
+
param :concern, Hash, :required => true
|
895
|
+
param :name, String, 'Name of a :resource'
|
896
|
+
param :resource_type, ['standard','vip']
|
897
|
+
end
|
898
|
+
def create
|
899
|
+
# ...
|
900
|
+
end
|
901
|
+
|
902
|
+
api :GET, '/:resource_id/:custom_subst'
|
903
|
+
def custom
|
904
|
+
# ...
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
908
|
+
# users_controller.rb
|
909
|
+
class UsersController < ApplicationController
|
910
|
+
|
911
|
+
resource_description { resource_id 'customers' }
|
912
|
+
|
913
|
+
apipie_concern_subst(:custom_subst => 'custom', :resource => 'customer')
|
914
|
+
include UsersModule
|
915
|
+
|
916
|
+
# the following paths are documented
|
917
|
+
# api :GET, '/users'
|
918
|
+
# api :GET, '/customers/:id', 'Show a customer'
|
919
|
+
# api :POST, '/customers', 'Create a customer'
|
920
|
+
# param :customer, :required => true do
|
921
|
+
# param :name, String, 'Name of a customer'
|
922
|
+
# param :customer_type, ['standard', 'vip']
|
923
|
+
# end
|
924
|
+
# api :GET, '/customers/:custom'
|
925
|
+
end
|
926
|
+
```
|
927
|
+
|
928
|
+
Sometimes, it\'s needed to extend an existing controller method with
|
929
|
+
additional parameters (usually when extending exiting API from
|
930
|
+
plugins/rails engines). The concern can be also used for this purposed,
|
931
|
+
using `update_api` method. The params defined in this block
|
932
|
+
are merged with the params of the original method in the controller this
|
933
|
+
concern is included to.
|
934
|
+
|
935
|
+
### Example
|
936
|
+
|
937
|
+
``` ruby
|
938
|
+
module Concerns
|
939
|
+
module OauthConcern
|
940
|
+
extend Apipie::DSL::Concern
|
941
|
+
|
942
|
+
update_api(:create, :update) do
|
943
|
+
param :user, Hash do
|
944
|
+
param :oauth, String, :desc => 'oauth param'
|
945
|
+
end
|
946
|
+
end
|
947
|
+
end
|
948
|
+
end
|
949
|
+
```
|
950
|
+
|
951
|
+
The concern needs to be included to the controller after the methods are
|
952
|
+
defined (either at the end of the class, or by using
|
953
|
+
`Controller.send(:include, Concerns::OauthConcern)`.
|
954
|
+
|
955
|
+
## Response validation
|
956
|
+
|
957
|
+
The swagger definitions created by Apipie can be used to auto-generate
|
958
|
+
clients that access the described APIs. Those clients will break if the
|
959
|
+
responses returned from the API do not match the declarations. As such,
|
960
|
+
it is very important to include unit tests that validate the actual
|
961
|
+
responses against the swagger definitions.
|
962
|
+
|
963
|
+
The implemented mechanism provides two ways to include such validations
|
964
|
+
in RSpec unit tests: manual (using an RSpec matcher) and automated (by
|
965
|
+
injecting a test into the http operations \'get\', \'post\', raising an
|
966
|
+
error if there is no match).
|
967
|
+
|
968
|
+
### Example of the manual mechanism:
|
969
|
+
|
970
|
+
``` ruby
|
971
|
+
require 'apipie/rspec/response_validation_helper'
|
972
|
+
|
973
|
+
RSpec.describe MyController, :type => :controller, :show_in_doc => true do
|
974
|
+
|
975
|
+
describe "GET stuff with response validation" do
|
976
|
+
render_views # this makes sure the 'get' operation will actually
|
977
|
+
# return the rendered view even though this is a Controller spec
|
978
|
+
|
979
|
+
it "does something" do
|
980
|
+
response = get :index, {format: :json}
|
981
|
+
|
982
|
+
# the following expectation will fail if the returned object
|
983
|
+
# does not match the 'returns' declaration in the Controller,
|
984
|
+
# or if there is no 'returns' declaration for the returned
|
985
|
+
# HTTP status code
|
986
|
+
expect(response).to match_declared_responses
|
987
|
+
end
|
988
|
+
end
|
989
|
+
end
|
990
|
+
```
|
991
|
+
|
992
|
+
### Example of the automated mechanism:
|
993
|
+
|
994
|
+
``` ruby
|
995
|
+
require 'apipie/rspec/response_validation_helper'
|
996
|
+
|
997
|
+
RSpec.describe MyController, :type => :controller, :show_in_doc => true do
|
998
|
+
|
999
|
+
describe "GET stuff with response validation" do
|
1000
|
+
render_views
|
1001
|
+
auto_validate_rendered_views
|
1002
|
+
|
1003
|
+
it "does something" do
|
1004
|
+
get :index, {format: :json}
|
1005
|
+
end
|
1006
|
+
it "does something else" do
|
1007
|
+
get :another_index, {format: :json}
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
describe "GET stuff without response validation" do
|
1012
|
+
it "does something" do
|
1013
|
+
get :index, {format: :json}
|
1014
|
+
end
|
1015
|
+
it "does something else" do
|
1016
|
+
get :another_index, {format: :json}
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
```
|
1021
|
+
|
1022
|
+
# Configuration Reference
|
1023
|
+
|
1024
|
+
Create a configuration file in e.g. `/config/initializers/apipie.rb`.
|
1025
|
+
You can set the application name, footer text, API and documentation
|
1026
|
+
base URL and turn off validations. You can also choose your favorite
|
1027
|
+
markup language for full descriptions.
|
1028
|
+
|
1029
|
+
`app_name`
|
1030
|
+
|
1031
|
+
Name of your application; used in breadcrumbs navigation.
|
1032
|
+
|
1033
|
+
`copyright`
|
1034
|
+
|
1035
|
+
Copyright information (shown in page footer).
|
1036
|
+
|
1037
|
+
`compress_examples`
|
1038
|
+
|
1039
|
+
If `true` recorded examples are compressed using `Zlib`. Useful for
|
1040
|
+
big test-suits.
|
1041
|
+
|
1042
|
+
`doc_base_url`
|
1043
|
+
|
1044
|
+
Documentation frontend base url.
|
1045
|
+
|
1046
|
+
`api_base_url`
|
1047
|
+
|
1048
|
+
Base url for default version of your API. To set it for specific
|
1049
|
+
version use `config.api_base_url[version] = url`.
|
1050
|
+
|
1051
|
+
`default_version`
|
1052
|
+
|
1053
|
+
Default API version to be used (1.0 by default)
|
1054
|
+
|
1055
|
+
`validate`
|
1056
|
+
|
1057
|
+
Parameters validation is turned off when set to false. When set to
|
1058
|
+
`:explicitly`, you must invoke parameter validation yourself by
|
1059
|
+
calling controller method `apipie_validations` (typically in a
|
1060
|
+
before_action). When set to `:implicitly` (or just true), your
|
1061
|
+
controller\'s action methods are wrapped with generated methods
|
1062
|
+
which call `apipie_validations`, and then call the action method.
|
1063
|
+
(`:implicitly` by default)
|
1064
|
+
|
1065
|
+
`validate_value`
|
1066
|
+
|
1067
|
+
Check the value of params against specified validators (true by default)
|
1068
|
+
|
1069
|
+
`validate_presence`
|
1070
|
+
|
1071
|
+
Check the params presence against the documentation.
|
1072
|
+
|
1073
|
+
`validate_key`
|
1074
|
+
|
1075
|
+
Check the received params to ensure they are defined in the API.
|
1076
|
+
(false by default)
|
1077
|
+
|
1078
|
+
`action_on_non_validated_keys`
|
1079
|
+
|
1080
|
+
Either `:raise` or `:skip`. If `validate_key` fails, raise error or
|
1081
|
+
delete the non-validated key from the params and log the key (`:raise` by default)
|
1082
|
+
|
1083
|
+
`process_params`
|
1084
|
+
|
1085
|
+
Process and extract the parameter defined from the params of the
|
1086
|
+
request to the api_params variable
|
1087
|
+
|
1088
|
+
`app_info`
|
1089
|
+
|
1090
|
+
Application long description.
|
1091
|
+
|
1092
|
+
`reload_controllers`
|
1093
|
+
|
1094
|
+
Set to enable/disable reloading controllers (and the documentation
|
1095
|
+
with it). Enabled by default in development.
|
1096
|
+
|
1097
|
+
`api_controllers_matcher`
|
1098
|
+
|
1099
|
+
For reloading to work properly you need to specify where your API
|
1100
|
+
controllers are. Can be an array if multiple paths are needed
|
1101
|
+
|
1102
|
+
`api_action_matcher`
|
1103
|
+
|
1104
|
+
Determines the strategy to identity the correct controller action.
|
1105
|
+
Needs to be a class that implements a `.call(controller)` method
|
1106
|
+
|
1107
|
+
`api_routes`
|
1108
|
+
|
1109
|
+
Set if your application uses a custom API router, different from the
|
1110
|
+
Rails default
|
1111
|
+
|
1112
|
+
`routes_formatter`
|
1113
|
+
|
1114
|
+
An object providing the translation from the Rails routes to the
|
1115
|
+
format usable in the documentation when using the `api!`
|
1116
|
+
keyword. By default, the `Apipie::RoutesFormatter` is used.
|
1117
|
+
|
1118
|
+
`markup`
|
1119
|
+
|
1120
|
+
You can choose markup language for descriptions of your application,
|
1121
|
+
resources and methods. RDoc is the default but you can choose from
|
1122
|
+
Apipie::Markup::Markdown.new or Apipie::Markup::Textile.new. In
|
1123
|
+
order to use Markdown you need Maruku gem and for Textile you need
|
1124
|
+
RedCloth. Add those to your gemfile and run bundle if you want to
|
1125
|
+
use them. You can also add any other markup language processor.
|
1126
|
+
|
1127
|
+
`layout`
|
1128
|
+
|
1129
|
+
Name of a layout template to use instead of Apipie\'s layout. You
|
1130
|
+
can use Apipie.include_stylesheets and Apipie.include_javascripts
|
1131
|
+
helpers to include Apipie\'s stylesheets and javascripts.
|
1132
|
+
|
1133
|
+
`ignored`
|
1134
|
+
|
1135
|
+
An array of controller names (strings) (might include actions as
|
1136
|
+
well) to be ignored when generating the documentation e.g.
|
1137
|
+
`%w[Api::CommentsController Api::PostsController#post]`
|
1138
|
+
|
1139
|
+
`namespaced_resources`
|
1140
|
+
|
1141
|
+
Use controller paths instead of controller names as resource id.
|
1142
|
+
This prevents same named controllers overwriting each other.
|
1143
|
+
|
1144
|
+
`authenticate`
|
1145
|
+
|
1146
|
+
Pass a proc in order to authenticate user. Pass nil for no
|
1147
|
+
authentication (by default).
|
1148
|
+
|
1149
|
+
`authorize`
|
1150
|
+
|
1151
|
+
Pass a proc in order to authorize controllers and methods. The Proc
|
1152
|
+
is evaluated in the controller context.
|
1153
|
+
|
1154
|
+
`show_all_examples`
|
1155
|
+
|
1156
|
+
Set this to true to set show_in_doc=1 in all recorded examples
|
1157
|
+
|
1158
|
+
`ignore_allow_blank_false`
|
1159
|
+
|
1160
|
+
`allow_blank: false` was incorrectly ignored up until
|
1161
|
+
version 0.6.0, this bug was fixed in 0.7.0 if you need the old
|
1162
|
+
behavior, set this to true
|
1163
|
+
|
1164
|
+
`link_extension`
|
1165
|
+
|
1166
|
+
The extension to use for API pages (\'.html\' by default). Link
|
1167
|
+
extensions in static API docs cannot be changed from \'.html\'.
|
1168
|
+
|
1169
|
+
`languages`
|
1170
|
+
|
1171
|
+
List of languages the API documentation should be translated into.
|
1172
|
+
Empty by default.
|
1173
|
+
|
1174
|
+
`default_locale`
|
1175
|
+
|
1176
|
+
Locale used for generating documentation when no specific locale is
|
1177
|
+
set. Set to \'en\' by default.
|
1178
|
+
|
1179
|
+
`locale`
|
1180
|
+
|
1181
|
+
Pass locale setter/getter
|
1182
|
+
|
1183
|
+
``` ruby
|
1184
|
+
config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
|
1185
|
+
```
|
1186
|
+
|
1187
|
+
`translate`
|
1188
|
+
|
1189
|
+
Pass proc to translate strings using the localization library your
|
1190
|
+
project uses. For example see [Localization](#localization)
|
1191
|
+
|
1192
|
+
Example:
|
1193
|
+
|
1194
|
+
``` ruby
|
1195
|
+
Apipie.configure do |config|
|
1196
|
+
config.app_name = "Test app"
|
1197
|
+
config.copyright = "© 2012 Pavel Pokorny"
|
1198
|
+
config.doc_base_url = "/apidoc"
|
1199
|
+
config.api_base_url = "/api"
|
1200
|
+
config.validate = false
|
1201
|
+
config.markup = Apipie::Markup::Markdown.new
|
1202
|
+
config.reload_controllers = Rails.env.development?
|
1203
|
+
config.api_controllers_matcher = File.join(Rails.root, "app", "controllers", "**","*.rb")
|
1204
|
+
config.api_action_matcher = proc { |controller| controller.params[:action] }
|
1205
|
+
config.api_routes = Rails.application.routes
|
1206
|
+
config.app_info["1.0"] = "
|
1207
|
+
This is where you can inform user about your application and API
|
1208
|
+
in general.
|
1209
|
+
"
|
1210
|
+
config.authenticate = Proc.new do
|
1211
|
+
authenticate_or_request_with_http_basic do |username, password|
|
1212
|
+
username == "test" && password == "supersecretpassword"
|
1213
|
+
end
|
1214
|
+
end
|
1215
|
+
config.authorize = Proc.new do |controller, method, doc|
|
1216
|
+
!method # show all controller doc, but no method docs.
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
```
|
1220
|
+
|
1221
|
+
`checksum_path`
|
1222
|
+
|
1223
|
+
Used in ChecksumInHeaders middleware (see [JSON
|
1224
|
+
checksums](#json-checksums) for more info). It contains path
|
1225
|
+
prefix(es) where the header with checksum is added. If set to nil,
|
1226
|
+
checksum is added in headers in every response. e.g.
|
1227
|
+
`%w[/api /apipie]`
|
1228
|
+
|
1229
|
+
`update_checksum`
|
1230
|
+
|
1231
|
+
If set to `true`, the checksum is recalculated with every
|
1232
|
+
documentation_reload call
|
1233
|
+
|
1234
|
+
# Rails Routes Integration
|
1235
|
+
|
1236
|
+
Apipie is able to load the information about the paths based on the
|
1237
|
+
routes defined in the Rails application, by using the `api!`
|
1238
|
+
keyword in the DSL.
|
1239
|
+
|
1240
|
+
It should be usable out of box, however, one might want to do some
|
1241
|
+
customization (such as omitting some implicit parameters in the path
|
1242
|
+
etc.). For this kind of customizations one can create a new formatter
|
1243
|
+
and pass as the `Apipie.configuration.routes_formatter` option, like
|
1244
|
+
this:
|
1245
|
+
|
1246
|
+
``` ruby
|
1247
|
+
class MyFormatter < Apipie::RoutesFormatter
|
1248
|
+
def format_path(route)
|
1249
|
+
super.gsub(/\(.*?\)/, '').gsub('//','') # hide all implicit parameters
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
Apipie.configure do |config|
|
1254
|
+
...
|
1255
|
+
config.routes_formatter = MyFormatter.new
|
1256
|
+
...
|
1257
|
+
end
|
1258
|
+
```
|
1259
|
+
|
1260
|
+
A similar way can be used to influence things like order, or a
|
1261
|
+
description of the loaded APIs, even omitting some paths if needed.
|
1262
|
+
|
1263
|
+
# Processing
|
1264
|
+
|
1265
|
+
The goal is to extract and pre-process parameters of the request.
|
1266
|
+
|
1267
|
+
For example Rails, by default, transforms an empty array to nil value.
|
1268
|
+
Perhaps you want to transform it again into an empty array. Or you want
|
1269
|
+
to support an enumeration type (comma separated values) and you want to
|
1270
|
+
automatically transform this string into an array.
|
1271
|
+
|
1272
|
+
To use it, set the `process_params` configuration variable to true.
|
1273
|
+
|
1274
|
+
Also by using `as` you can separate your API parameter names from the
|
1275
|
+
names you are using inside your code.
|
1276
|
+
|
1277
|
+
To implement it, you just have to write a process_value function in your
|
1278
|
+
validator:
|
1279
|
+
|
1280
|
+
For an enumeration type:
|
1281
|
+
|
1282
|
+
``` ruby
|
1283
|
+
def process_value(value)
|
1284
|
+
value ? value.split(',') : []
|
1285
|
+
end
|
1286
|
+
```
|
1287
|
+
|
1288
|
+
# Validators
|
1289
|
+
|
1290
|
+
Every parameter needs to have an associated validator. For now there are
|
1291
|
+
some basic validators. You can always provide your own to achieve
|
1292
|
+
complex results.
|
1293
|
+
|
1294
|
+
If validations are enabled (default state) the parameters of every
|
1295
|
+
request are validated. If the value is wrong an +ArgumentError+
|
1296
|
+
exception is raised and can be rescued and processed. It contains a
|
1297
|
+
description of the parameter value expectations. Validations can be
|
1298
|
+
turned off in the configuration file.
|
1299
|
+
|
1300
|
+
Here is an example of how to rescue and process a +ParamMissing+ or
|
1301
|
+
+ParamInvalid+ error from within the ApplicationController.
|
1302
|
+
|
1303
|
+
``` ruby
|
1304
|
+
class ApplicationController < ActionController::Base
|
1305
|
+
|
1306
|
+
# ParamError is superclass of ParamMissing, ParamInvalid
|
1307
|
+
rescue_from Apipie::ParamError do |e|
|
1308
|
+
render text: e.message, status: :unprocessable_entity
|
1309
|
+
end
|
1310
|
+
|
1311
|
+
# ...
|
1312
|
+
end
|
1313
|
+
```
|
1314
|
+
|
1315
|
+
Parameter validation normally happens after before_actions, just before
|
1316
|
+
your controller method is invoked. If you prefer to control when
|
1317
|
+
parameter validation occurs, set the configuration parameter `validate`
|
1318
|
+
to `:explicitly`. You must then call the `apipie_validations` method
|
1319
|
+
yourself, e.g.:
|
1320
|
+
|
1321
|
+
``` ruby
|
1322
|
+
before_action :apipie_validations
|
1323
|
+
```
|
1324
|
+
|
1325
|
+
This is useful if you have before_actions which use parameter values:
|
1326
|
+
just add them after the `apipie_validations` before_action.
|
1327
|
+
|
1328
|
+
## TypeValidator
|
1329
|
+
|
1330
|
+
Check the parameter type. Only String, Integer, Hash and Array are
|
1331
|
+
supported for the sake of simplicity. Read more to find out how to add
|
1332
|
+
your own validator.
|
1333
|
+
|
1334
|
+
``` ruby
|
1335
|
+
param :session, String, :desc => "user is logged in", :required => true
|
1336
|
+
param :facts, Hash, :desc => "Additional optional facts about the user"
|
1337
|
+
```
|
1338
|
+
|
1339
|
+
## RegexpValidator
|
1340
|
+
|
1341
|
+
Check parameter value against given regular expression.
|
1342
|
+
|
1343
|
+
``` ruby
|
1344
|
+
param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
|
1345
|
+
```
|
1346
|
+
|
1347
|
+
## EnumValidator
|
1348
|
+
|
1349
|
+
Check if parameter value is included in the given array.
|
1350
|
+
|
1351
|
+
``` ruby
|
1352
|
+
param :enum_param, [100, "one", "two", 1, 2], :desc => "enum validator"
|
1353
|
+
```
|
1354
|
+
|
1355
|
+
## ProcValidator
|
1356
|
+
|
1357
|
+
If you need more complex validation and you know you won\'t reuse it,
|
1358
|
+
you can use the Proc/lambda validator. Provide your own Proc, taking the
|
1359
|
+
value of the parameter as the only argument. Return true if value passes
|
1360
|
+
validation or return some text about what is wrong otherwise. Don't
|
1361
|
+
use the keyword *return* if you provide an instance of Proc (with lambda
|
1362
|
+
it is ok), just use the last statement return property of ruby.
|
1363
|
+
|
1364
|
+
``` ruby
|
1365
|
+
param :proc_param, lambda { |val|
|
1366
|
+
val == "param value" ? true : "The only good value is 'param value'."
|
1367
|
+
}, :desc => "proc validator"
|
1368
|
+
```
|
1369
|
+
|
1370
|
+
## HashValidator
|
1371
|
+
|
1372
|
+
You can describe hash parameters in depth if you provide a block with a
|
1373
|
+
description of nested values.
|
1374
|
+
|
1375
|
+
``` ruby
|
1376
|
+
param :user, Hash, :desc => "User info" do
|
1377
|
+
param :username, String, :desc => "Username for login", :required => true
|
1378
|
+
param :password, String, :desc => "Password for login", :required => true
|
1379
|
+
param :membership, ["standard","premium"], :desc => "User membership"
|
1380
|
+
end
|
1381
|
+
```
|
1382
|
+
|
1383
|
+
## NilValidator
|
1384
|
+
|
1385
|
+
In fact there isn\'t any NilValidator, but setting it to nil can be used
|
1386
|
+
to override parameters described on the resource level.
|
1387
|
+
|
1388
|
+
``` ruby
|
1389
|
+
param :user, nil
|
1390
|
+
def destroy
|
1391
|
+
#...
|
1392
|
+
end
|
1393
|
+
```
|
1394
|
+
|
1395
|
+
## NumberValidator
|
1396
|
+
|
1397
|
+
Check if the parameter is a positive integer number or zero
|
1398
|
+
|
1399
|
+
``` ruby
|
1400
|
+
param :product_id, :number, :desc => "Identifier of the product", :required => true
|
1401
|
+
param :quantity, :number, :desc => "Number of products to order", :required => true
|
1402
|
+
```
|
1403
|
+
|
1404
|
+
DecimalValidator \-\-\-\-\-\-\-\-\-\-\-\-\--
|
1405
|
+
|
1406
|
+
Check if the parameter is a decimal number
|
1407
|
+
|
1408
|
+
``` ruby
|
1409
|
+
param :latitude, :decimal, :desc => "Geographic latitude", :required => true
|
1410
|
+
param :longitude, :decimal, :desc => "Geographic longitude", :required => true
|
1411
|
+
```
|
1412
|
+
|
1413
|
+
## ArrayValidator
|
1414
|
+
|
1415
|
+
Check if the parameter is an array
|
1416
|
+
|
1417
|
+
Additional options
|
1418
|
+
|
1419
|
+
`of`
|
1420
|
+
|
1421
|
+
Specify the type of items. If not given it accepts an array of any item type
|
1422
|
+
|
1423
|
+
`in`
|
1424
|
+
|
1425
|
+
Specify an array of valid item values.
|
1426
|
+
|
1427
|
+
### Examples
|
1428
|
+
|
1429
|
+
Assert `things` is an array of any items
|
1430
|
+
|
1431
|
+
``` ruby
|
1432
|
+
param :things, Array
|
1433
|
+
```
|
1434
|
+
|
1435
|
+
Assert `hits` must be an array of integer values
|
1436
|
+
|
1437
|
+
``` ruby
|
1438
|
+
param :hits, Array, of: Integer
|
1439
|
+
```
|
1440
|
+
|
1441
|
+
Assert `colors` must be an array of valid string values
|
1442
|
+
|
1443
|
+
``` ruby
|
1444
|
+
param :colors, Array, in: ["red", "green", "blue"]
|
1445
|
+
```
|
1446
|
+
|
1447
|
+
The retrieving of valid items can be deferred until needed using a
|
1448
|
+
lambda. It is evaluated only once
|
1449
|
+
|
1450
|
+
``` ruby
|
1451
|
+
param :colors, Array, in: -> { Color.all.pluck(:name) }
|
1452
|
+
```
|
1453
|
+
|
1454
|
+
### NestedValidator
|
1455
|
+
|
1456
|
+
You can describe nested parameters in depth if you provide a block with
|
1457
|
+
a description of nested values.
|
1458
|
+
|
1459
|
+
``` ruby
|
1460
|
+
param :comments, Array, :desc => "User comments" do
|
1461
|
+
param :name, String, :desc => "Name of the comment", :required => true
|
1462
|
+
param :comment, String, :desc => "Full comment", :required => true
|
1463
|
+
end
|
1464
|
+
```
|
1465
|
+
|
1466
|
+
## Adding custom validator
|
1467
|
+
|
1468
|
+
Only basic validators are included but it is really easy to add your
|
1469
|
+
own. Create a new initializer with a subclass of
|
1470
|
+
Apipie::Validator::BaseValidator. Two methods are required to implement
|
1471
|
+
this - instance method `validate(value)` and class method
|
1472
|
+
`build(param_description, argument, options, block)`.
|
1473
|
+
|
1474
|
+
When searching for the validator +build+ method, every subclass of
|
1475
|
+
Apipie::Validator::BaseValidator is called. The first one that returns
|
1476
|
+
the constructed validator object is used.
|
1477
|
+
|
1478
|
+
Example: Adding IntegerValidator
|
1479
|
+
|
1480
|
+
We want to check if the parameter value is an integer like this:
|
1481
|
+
|
1482
|
+
``` ruby
|
1483
|
+
param :id, Integer, :desc => "Company ID"
|
1484
|
+
```
|
1485
|
+
|
1486
|
+
So we create apipie_validators.rb initializer with this content:
|
1487
|
+
|
1488
|
+
``` ruby
|
1489
|
+
class IntegerValidator < Apipie::Validator::BaseValidator
|
1490
|
+
|
1491
|
+
def initialize(param_description, argument)
|
1492
|
+
super(param_description)
|
1493
|
+
@type = argument
|
1494
|
+
end
|
1495
|
+
|
1496
|
+
def validate(value)
|
1497
|
+
return false if value.nil?
|
1498
|
+
!!(value.to_s =~ /^[-+]?[0-9]+$/)
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
def self.build(param_description, argument, options, block)
|
1502
|
+
if argument == Integer
|
1503
|
+
self.new(param_description, argument)
|
1504
|
+
end
|
1505
|
+
end
|
1506
|
+
|
1507
|
+
def description
|
1508
|
+
"Must be #{@type}."
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
def expected_type
|
1512
|
+
'numeric'
|
1513
|
+
end
|
1514
|
+
end
|
1515
|
+
```
|
1516
|
+
|
1517
|
+
Parameters of the build method:
|
1518
|
+
|
1519
|
+
`param_description`
|
1520
|
+
|
1521
|
+
Instance of Apipie::ParamDescription contains all given information about the validated parameter.
|
1522
|
+
|
1523
|
+
`argument`
|
1524
|
+
|
1525
|
+
Specified validator; in our example it is +Integer+
|
1526
|
+
|
1527
|
+
`options`
|
1528
|
+
|
1529
|
+
Hash with specified options, for us just `{:desc => "Company ID"}`
|
1530
|
+
|
1531
|
+
`block`
|
1532
|
+
|
1533
|
+
Block converted into Proc, use it as you desire. In this example nil.
|
1534
|
+
|
1535
|
+
If your validator includes valid values that respond true to
|
1536
|
+
`.blank?`, you should also define:
|
1537
|
+
|
1538
|
+
``` ruby
|
1539
|
+
def ignore_allow_blank?
|
1540
|
+
true
|
1541
|
+
end
|
1542
|
+
```
|
1543
|
+
|
1544
|
+
so that the validation does not fail for valid values.
|
1545
|
+
|
1546
|
+
# Versioning
|
1547
|
+
|
1548
|
+
Every resource/method can belong to one or more versions. The version is
|
1549
|
+
specified with the `api_version` DSL keyword. When not
|
1550
|
+
specified, the resource belongs to `config.default_version`
|
1551
|
+
(\"1.0\" by default)
|
1552
|
+
|
1553
|
+
``` ruby
|
1554
|
+
resource_description do
|
1555
|
+
api_versions "1", "2"
|
1556
|
+
end
|
1557
|
+
|
1558
|
+
api :GET, "/api/users/", "List: users"
|
1559
|
+
api_version "1"
|
1560
|
+
def index
|
1561
|
+
# ...
|
1562
|
+
end
|
1563
|
+
|
1564
|
+
api :GET, "/api/users/", "List: users", :deprecated => true
|
1565
|
+
```
|
1566
|
+
|
1567
|
+
In the example above we say the whole controller/resource is defined for
|
1568
|
+
versions \"1\" and \"2\", but we override this by explicitly saying
|
1569
|
+
`index` belongs only to version \"1\". Also, inheritance
|
1570
|
+
works (therefore we can specify the api_version for the parent
|
1571
|
+
controller, and all children will know about that). Routes can be
|
1572
|
+
flagged as deprecated, and an annotation will be added to them when
|
1573
|
+
viewing in the API documentation.
|
1574
|
+
|
1575
|
+
From the Apipie API perspective, the resources belong to the version.
|
1576
|
+
With versioning, there are paths like this provided by apipie:
|
1577
|
+
|
1578
|
+
```
|
1579
|
+
/apipie/1/users/index
|
1580
|
+
/apipie/2/users/index
|
1581
|
+
```
|
1582
|
+
|
1583
|
+
When not specifying the version explicitly in the path (or in DSL),
|
1584
|
+
default version (`Apipie.configuration.default_version`) is
|
1585
|
+
used instead (\"1.0\" by default). Therefore, an application that
|
1586
|
+
doesn\'t need versioning should work as before.
|
1587
|
+
|
1588
|
+
The static page generator takes a version parameter (or uses default).
|
1589
|
+
|
1590
|
+
You can specify the versions for the examples, with the
|
1591
|
+
`versions` keyword. It specifies the versions the example is
|
1592
|
+
used for. When not specified, it\'s shown in all versions with the given
|
1593
|
+
method.
|
1594
|
+
|
1595
|
+
When referencing or querying the resource/method descripion, this format
|
1596
|
+
should be used: \"version#resource#method\". When not specified, the
|
1597
|
+
default version is used instead.
|
1598
|
+
|
1599
|
+
# Markup
|
1600
|
+
|
1601
|
+
The default markup language is
|
1602
|
+
[RDoc](https://rdoc.github.io/rdoc/RDoc/Markup.html). It can be changed
|
1603
|
+
in the config file (`config.markup=`) to one of these:
|
1604
|
+
|
1605
|
+
Markdown
|
1606
|
+
|
1607
|
+
Use Apipie::Markup::Markdown.new. You need Maruku gem.
|
1608
|
+
|
1609
|
+
Textile
|
1610
|
+
|
1611
|
+
Use Apipie::Markup::Textile.new. You need RedCloth gem.
|
1612
|
+
|
1613
|
+
Or provide you own object with a `to_html(text)` method. For
|
1614
|
+
inspiration, this is how Textile markup usage is implemented:
|
1615
|
+
|
1616
|
+
``` ruby
|
1617
|
+
class Textile
|
1618
|
+
def initialize
|
1619
|
+
require 'RedCloth'
|
1620
|
+
end
|
1621
|
+
def to_html(text)
|
1622
|
+
RedCloth.new(text).to_html
|
1623
|
+
end
|
1624
|
+
end
|
1625
|
+
```
|
1626
|
+
|
1627
|
+
# Localization
|
1628
|
+
|
1629
|
+
Apipie has support for localized API documentation in both formats (JSON
|
1630
|
+
and HTML). Apipie uses the library I18n for localization of itself.
|
1631
|
+
Check `config/locales` directory for available translations.
|
1632
|
+
|
1633
|
+
A major part of strings in the documentation comes from the API. As
|
1634
|
+
preferences regarding localization libraries differ amongst project,
|
1635
|
+
Apipie needs to know how to set the locale for your project, and how to
|
1636
|
+
translate a string using the library your project uses. That can be done
|
1637
|
+
using lambdas in configuration.
|
1638
|
+
|
1639
|
+
Sample configuration when your project uses FastGettext
|
1640
|
+
|
1641
|
+
``` ruby
|
1642
|
+
Apipie.configure do |config|
|
1643
|
+
...
|
1644
|
+
config.languages = ['en', 'cs']
|
1645
|
+
config.default_locale = 'en'
|
1646
|
+
config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
|
1647
|
+
config.translate = lambda do |str, loc|
|
1648
|
+
old_loc = FastGettext.locale
|
1649
|
+
FastGettext.set_locale(loc)
|
1650
|
+
trans = _(str)
|
1651
|
+
FastGettext.set_locale(old_loc)
|
1652
|
+
trans
|
1653
|
+
end
|
1654
|
+
end
|
1655
|
+
```
|
1656
|
+
|
1657
|
+
And the strings in the API documentation need to be marked with the
|
1658
|
+
`N_()` function
|
1659
|
+
|
1660
|
+
``` ruby
|
1661
|
+
api :GET, "/users/:id", N_("Show user profile")
|
1662
|
+
param :session, String, :desc => N_("user is logged in"), :required => true
|
1663
|
+
```
|
1664
|
+
|
1665
|
+
When your project use I18n, localization related configuration could
|
1666
|
+
appear as follows
|
1667
|
+
|
1668
|
+
``` ruby
|
1669
|
+
Apipie.configure do |config|
|
1670
|
+
...
|
1671
|
+
config.languages = ['en', 'cs']
|
1672
|
+
config.default_locale = 'en'
|
1673
|
+
config.locale = lambda { |loc| loc ? I18n.locale = loc : I18n.locale }
|
1674
|
+
config.translate = lambda do |str, loc|
|
1675
|
+
return '' if str.blank?
|
1676
|
+
I18n.t str, locale: loc, scope: 'doc'
|
1677
|
+
end
|
1678
|
+
end
|
1679
|
+
```
|
1680
|
+
|
1681
|
+
And the strings in the API documentation needs to be in the form of
|
1682
|
+
translation keys
|
1683
|
+
|
1684
|
+
``` ruby
|
1685
|
+
api :GET, "/users/:id", "show_user_profile"
|
1686
|
+
param :session, String, :desc => "user_is_logged_in", :required => true
|
1687
|
+
```
|
1688
|
+
|
1689
|
+
The localized versions of the documentation are distinguished by
|
1690
|
+
language in the filename. E.g. `doc/apidoc/apidoc.cs.html` is static
|
1691
|
+
documentation in the Czech language. If the language is missing, e.g.
|
1692
|
+
`doc/apidoc/apidoc.html`, the documentation is localized with the
|
1693
|
+
`default_locale`.
|
1694
|
+
|
1695
|
+
The dynamic documentation follows the same schema. The
|
1696
|
+
`http://localhost:3000/apidoc/v1.cs.html` is documentation for version
|
1697
|
+
\'1\' of the API in the Czech language. For JSON descriptions, the API
|
1698
|
+
applies the same format: `http://localhost:3000/apidoc/v1.cs.json`
|
1699
|
+
|
1700
|
+
# Modifying Views
|
1701
|
+
|
1702
|
+
To modify the views of your documentation, run `rails g apipie:views`.
|
1703
|
+
This will copy the Apipie views to `app/views/apipie/apipies` and
|
1704
|
+
`app/views/layouts/apipie`.
|
1705
|
+
|
1706
|
+
# Static files
|
1707
|
+
|
1708
|
+
To generate a static version of documentation (perhaps to put it on your
|
1709
|
+
project site or something), run the `rake apipie:static` task. It will
|
1710
|
+
create a set of HTML files (multi-pages, single-page, plain) in your doc
|
1711
|
+
directory. If you prefer a JSON version run `rake apipie:static_json`.
|
1712
|
+
By default the documentation for the default API version is used. You
|
1713
|
+
can specify the version with `rake apipie:static[2.0]`
|
1714
|
+
|
1715
|
+
When you want to avoid any unnecessary computation in production mode,
|
1716
|
+
you can generate a cache with `rake apipie:cache` and configure the app
|
1717
|
+
to use it in production with `config.use_cache = Rails.env.production?`
|
1718
|
+
|
1719
|
+
Default cache dir is `File.join(Rails.root, "public", "apipie-cache")`,
|
1720
|
+
you can change it to where you want, example:
|
1721
|
+
`config.cache_dir = File.join(Rails.root, "doc", "apidoc")`.
|
1722
|
+
|
1723
|
+
If, for some complex cases, you need to generate/re-generate just part
|
1724
|
+
of the cache use `rake apipie:cache cache_part=index` resp.
|
1725
|
+
`rake apipie:cache cache_part=resources` To generate it for different
|
1726
|
+
locations for further processing use
|
1727
|
+
`rake apipie:cache OUT=/tmp/apipie_cache`.
|
1728
|
+
|
1729
|
+
# Static Swagger (OpenAPI 2.0) files
|
1730
|
+
|
1731
|
+
To generate a static Swagger definition file from the api, run
|
1732
|
+
`rake apipie:static_swagger_json`. By default the documentation for the
|
1733
|
+
default API version is used. You can specify the version with
|
1734
|
+
`rake apipie:static_swagger_json[2.0]`. A swagger file will be generated
|
1735
|
+
for each locale. The files will be generated in the same location as the
|
1736
|
+
static_json files, but instead of being named
|
1737
|
+
`schema_apipie[.locale].json`, they will be called
|
1738
|
+
`schema_swagger[.locale].json`.
|
1739
|
+
|
1740
|
+
## Specifying default values for parameters
|
1741
|
+
|
1742
|
+
Swagger allows method definitions to include an indication of the the
|
1743
|
+
default value for each parameter. To include such indications, use
|
1744
|
+
`:default_value => <some value>` in the parameter definition DSL. For
|
1745
|
+
example:
|
1746
|
+
|
1747
|
+
``` ruby
|
1748
|
+
param :do_something, Boolean, :desc => "take an action", :required => false, :default_value => false
|
1749
|
+
```
|
1750
|
+
|
1751
|
+
## Generated Warnings
|
1752
|
+
|
1753
|
+
The help identify potential improvements to your documentation, the
|
1754
|
+
swagger generation process issues warnings if it identifies various
|
1755
|
+
shortcomings of the DSL documentation. Each warning has a code to allow
|
1756
|
+
selective suppression (see swagger-specific configuration below)
|
1757
|
+
|
1758
|
+
| Error Code | Description |
|
1759
|
+
|------------|-------------------------------------------------------------------------------------|
|
1760
|
+
| 100 | Missing short description for method |
|
1761
|
+
| 101 | Added missing / at beginning of path |
|
1762
|
+
| 102 | No return codes specified for method |
|
1763
|
+
| 103 | A parameter is a generic Hash without an internal type specification |
|
1764
|
+
| 104 | A parameter is an 'in-path' parameter, but specified as 'not required' in the DSL |
|
1765
|
+
| 105 | A parameter is optional but does not have a default value specified |
|
1766
|
+
| 106 | A parameter was omitted from the swagger output because it is a Hash without fields in a formData specification |
|
1767
|
+
| 107 | A path parameter is not described |
|
1768
|
+
| 108 | Inferring that a parameter type is boolean because described as an enum with `[false true]` values |
|
1769
|
+
|
1770
|
+
|
1771
|
+
## Swagger-Specific Configuration Parameters
|
1772
|
+
|
1773
|
+
There are several configuration parameters that determine the structure
|
1774
|
+
of the generated swagger file:
|
1775
|
+
|
1776
|
+
`config.generator.swagger.content_type_input`
|
1777
|
+
|
1778
|
+
- If the value is `:form_data` - the swagger file will indicate that
|
1779
|
+
the server consumes the content types
|
1780
|
+
`application/x-www-form-urlencoded` and `multipart/form-data`.
|
1781
|
+
Non-path parameters will have the value `"in": "formData"`. Note
|
1782
|
+
that parameters of type Hash that do not have any fields in them
|
1783
|
+
will *be omitted* from the resulting files, as there is no way to
|
1784
|
+
describe them in swagger.
|
1785
|
+
|
1786
|
+
- If the value is `:json` - the swagger file will indicate that the
|
1787
|
+
server consumes the content type `application/json`. All non-path
|
1788
|
+
parameters will be included in the schema of a single `"in": "body"`
|
1789
|
+
parameter of type `object`.
|
1790
|
+
|
1791
|
+
- You can specify the value of this configuration parameter as an
|
1792
|
+
additional input to the rake command (e.g.,
|
1793
|
+
`rake apipie:static_swagger_json[2.0,form_data]`).
|
1794
|
+
|
1795
|
+
`config.generator.swagger.json_input_uses_refs`
|
1796
|
+
|
1797
|
+
- This parameter is only relevant if `swagger.content_type_input` is
|
1798
|
+
`:json`.
|
1799
|
+
|
1800
|
+
- If `true`: the schema of the `"in": "body"` parameter of each method
|
1801
|
+
is given its own entry in the `definitions` section, and is
|
1802
|
+
referenced using `$ref` from the method definition.
|
1803
|
+
|
1804
|
+
- If `false`: the body parameter definitions are inlined within the
|
1805
|
+
method definitions.
|
1806
|
+
|
1807
|
+
`config.generator.swagger.include_warning_tags`
|
1808
|
+
|
1809
|
+
- If `true`: in addition to tagging methods with the name of the
|
1810
|
+
resource they belong to, methods for which warnings have been issued
|
1811
|
+
will be tagged with.
|
1812
|
+
|
1813
|
+
`config.generator.swagger.suppress_warnings`
|
1814
|
+
|
1815
|
+
- If `false`: no warnings will be suppressed
|
1816
|
+
|
1817
|
+
- If `true`: all warnings will be suppressed
|
1818
|
+
|
1819
|
+
- If an array of values (e.g., `[100,102,107]`), only the warnings
|
1820
|
+
identified by the numbers in the array will be suppressed.
|
1821
|
+
|
1822
|
+
`config.generator.swagger.api_host`
|
1823
|
+
|
1824
|
+
- The value to place in the swagger host field. Default is `localhost:3000`
|
1825
|
+
- If `nil` then then host field will not be included.
|
1826
|
+
|
1827
|
+
`config.generator.swagger.allow_additional_properties_in_response`
|
1828
|
+
|
1829
|
+
- If `false` (default): response descriptions in the generated swagger
|
1830
|
+
will include an `additional-properties: false` field
|
1831
|
+
|
1832
|
+
- If `true`: the `additional-properties: false` field will not be
|
1833
|
+
included in response object descriptions
|
1834
|
+
|
1835
|
+
`config.generator.swagger.schemes`
|
1836
|
+
|
1837
|
+
- An array of transport schemes that the API supports. This can
|
1838
|
+
include any combination of `http`, `https`, `ws` and `wss`. By
|
1839
|
+
default to encourage good security practices, `['https']` is
|
1840
|
+
specified.
|
1841
|
+
|
1842
|
+
`config:swagger.security_definitions`
|
1843
|
+
|
1844
|
+
- If the API requires authentication, you can specify details of the
|
1845
|
+
authentication mechanisms supported as a (Hash) value here. See
|
1846
|
+
\[<https://swagger.io/docs/specification/2-0/authentication/>\] for
|
1847
|
+
details of what values can be specified By default, no security is
|
1848
|
+
defined.
|
1849
|
+
|
1850
|
+
`config.generator.swagger.global_security`
|
1851
|
+
|
1852
|
+
- If the API requires authentication, you can specify which of the
|
1853
|
+
authentication mechanisms are supported by all API operations as an
|
1854
|
+
Array of hashes here. This should be used in conjunction with the
|
1855
|
+
mechanisms defined by `swagger.security_definitions`. See
|
1856
|
+
\[<https://swagger.io/docs/specification/2-0/authentication/>\] for
|
1857
|
+
details of what values can be specified By default, no security is
|
1858
|
+
defined.
|
1859
|
+
|
1860
|
+
`config.generator.swagger.skip_default_tags`
|
1861
|
+
|
1862
|
+
- By setting `false` (default): The resource name for e.g.
|
1863
|
+
`/pets/{petId}` will automatically be added as a tag `pets`. By
|
1864
|
+
setting `true`: The tags needs to be explicitly added to the
|
1865
|
+
resource using the DSL.
|
1866
|
+
|
1867
|
+
## Known limitations of the current implementation
|
1868
|
+
|
1869
|
+
- There is currently no way to document the structure and content-type
|
1870
|
+
of the data returned from a method
|
1871
|
+
- Recorded examples are currently not included in the generated
|
1872
|
+
swagger file
|
1873
|
+
- The apipie `formats` value is ignored.
|
1874
|
+
- It is not possible to specify the \"consumed\" content type on a
|
1875
|
+
per-method basis
|
1876
|
+
- It is not possible to leverage all of the parameter type/format
|
1877
|
+
capabilities of swagger
|
1878
|
+
- Only OpenAPI 2.0 is supported
|
1879
|
+
- Responses are defined inline and not as a \$ref
|
1880
|
+
- It is not possible to specify per-operation security requirements
|
1881
|
+
(only global)
|
1882
|
+
|
1883
|
+
# Dynamic Swagger generation
|
1884
|
+
|
1885
|
+
To generate swagger dynamically, use
|
1886
|
+
`http://localhost:3000/apipie.json?type=swagger`.
|
1887
|
+
|
1888
|
+
Note that authorization is not supported for dynamic swagger generation,
|
1889
|
+
so if `config.authorize` is defined, dynamic swagger generation will be
|
1890
|
+
disabled.
|
1891
|
+
|
1892
|
+
Dynamically generated swagger is not cached, and is always generated on
|
1893
|
+
the fly.
|
1894
|
+
|
1895
|
+
# JSON checksums
|
1896
|
+
|
1897
|
+
If the API client needs to be sure that the JSON didn\'t changed, add
|
1898
|
+
the `ApipieChecksumInHeaders` middleware in your rails app. It can add a
|
1899
|
+
checksum of the entire JSON document in the response headers.
|
1900
|
+
|
1901
|
+
```
|
1902
|
+
"Apipie-Checksum"=>"fb81460e7f4e78d059f826624bdf9504"
|
1903
|
+
```
|
1904
|
+
|
1905
|
+
[Apipie bindings](https://github.com/Apipie/apipie-bindings) uses this
|
1906
|
+
feature to refresh its JSON cache.
|
1907
|
+
|
1908
|
+
To set it up add the following to your `application.rb`
|
1909
|
+
|
1910
|
+
```
|
1911
|
+
require 'apipie/middleware/checksum_in_headers'
|
1912
|
+
# Add JSON checksum in headers for smarter caching
|
1913
|
+
config.middleware.use "Apipie::Middleware::ChecksumInHeaders"
|
1914
|
+
```
|
1915
|
+
|
1916
|
+
And in your apipie initializer allow checksum calculation
|
1917
|
+
|
1918
|
+
```
|
1919
|
+
Apipie.configuration.update_checksum = true
|
1920
|
+
```
|
1921
|
+
|
1922
|
+
By default the header is added to responses for `config.doc_base_url`
|
1923
|
+
and `/api`. It can be changed in configuration (see [Configuration
|
1924
|
+
Reference](#configuration-reference) for details).
|
1925
|
+
|
1926
|
+
The checksum calculation is lazy, and done with the first request. If
|
1927
|
+
you run with `use_cache = true`, do not forget to run the rake task
|
1928
|
+
`apipie:cache`.
|
1929
|
+
|
1930
|
+
# Tests Integration
|
1931
|
+
|
1932
|
+
Apipie integrates with automated testing in two ways. *Documentation
|
1933
|
+
bootstrapping* and *examples recording*.
|
1934
|
+
|
1935
|
+
## Documentation Bootstrapping
|
1936
|
+
|
1937
|
+
Let\'s say you have an application without REST API documentation.
|
1938
|
+
However you have a set of tests that are run against this API. A lot of
|
1939
|
+
information is already included in these tests, it just needs to be
|
1940
|
+
extracted somehow. Luckily, Apipie provides such a feature.
|
1941
|
+
|
1942
|
+
When running the tests, set the `APIPIE_RECORD=params` environment
|
1943
|
+
variable or call `Apipie.record('params')` from specs starter. You can
|
1944
|
+
either use it with functional tests:
|
1945
|
+
|
1946
|
+
```
|
1947
|
+
APIPIE_RECORD=params rake test:functionals
|
1948
|
+
```
|
1949
|
+
|
1950
|
+
or you can run your server with this param, in case you run the tests
|
1951
|
+
against running server:
|
1952
|
+
|
1953
|
+
```
|
1954
|
+
APIPIE_RECORD=params rails server
|
1955
|
+
```
|
1956
|
+
|
1957
|
+
When the process quits, the data from requests/responses are used to
|
1958
|
+
determine the documentation. It\'s quite raw, but it makes the initial
|
1959
|
+
phase much easier.
|
1960
|
+
|
1961
|
+
## Examples Recording
|
1962
|
+
|
1963
|
+
You can also use the tests to generate up-to-date examples for your
|
1964
|
+
code. Similar to the bootstrapping process, you can use it with
|
1965
|
+
functional tests or a running server, setting `APIPIE_RECORD=examples`
|
1966
|
+
or calling `Apipie.record('examples')` in your specs starter.
|
1967
|
+
|
1968
|
+
```
|
1969
|
+
APIPIE_RECORD=examples rake test:functionals
|
1970
|
+
APIPIE_RECORD=examples rails server
|
1971
|
+
```
|
1972
|
+
|
1973
|
+
The data is written into `doc/apipie_examples.yml`. By default, only the
|
1974
|
+
first example is shown for each action. You can customize this by
|
1975
|
+
setting the `show_in_doc` attribute at each example.
|
1976
|
+
|
1977
|
+
You can add a title to the examples (useful when showing more than one
|
1978
|
+
example per method) by adding a \'title\' attribute.
|
1979
|
+
|
1980
|
+
```
|
1981
|
+
--- !omap
|
1982
|
+
- announcements#index:
|
1983
|
+
- !omap
|
1984
|
+
- title: This is a custom title for this example
|
1985
|
+
- verb: :GET
|
1986
|
+
- path: /api/blabla/1
|
1987
|
+
- versions:
|
1988
|
+
- '1.0'
|
1989
|
+
- query:
|
1990
|
+
- request_data:
|
1991
|
+
- response_data:
|
1992
|
+
...
|
1993
|
+
- code: 200
|
1994
|
+
- show_in_doc: 1 # If 1, show. If 0, do not show.
|
1995
|
+
- recorded: true
|
1996
|
+
```
|
1997
|
+
|
1998
|
+
In RSpec you can add metadata to examples. We can use that feature to
|
1999
|
+
mark selected examples - the ones that perform the requests that we want
|
2000
|
+
to show as examples in the documentation.
|
2001
|
+
|
2002
|
+
For example, we can add `show_in_doc` to examples, like this:
|
2003
|
+
|
2004
|
+
``` ruby
|
2005
|
+
describe "This is the correct path" do
|
2006
|
+
it "some test", :show_in_doc do
|
2007
|
+
....
|
2008
|
+
end
|
2009
|
+
end
|
2010
|
+
|
2011
|
+
context "These are edge cases" do
|
2012
|
+
it "Can't authenticate" do
|
2013
|
+
....
|
2014
|
+
end
|
2015
|
+
|
2016
|
+
it "record not found" do
|
2017
|
+
....
|
2018
|
+
end
|
2019
|
+
end
|
2020
|
+
```
|
2021
|
+
|
2022
|
+
And then configure RSpec in this way:
|
2023
|
+
|
2024
|
+
``` ruby
|
2025
|
+
RSpec.configure do |config|
|
2026
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
2027
|
+
config.filter_run :show_in_doc => true if ENV['APIPIE_RECORD']
|
2028
|
+
end
|
2029
|
+
```
|
2030
|
+
|
2031
|
+
This way, when running in recording mode, only the tests that have been
|
2032
|
+
marked with the `:show_in_doc` metadata will be run, and hence only
|
2033
|
+
those will be used as examples.
|
2034
|
+
|
2035
|
+
## Caveats
|
2036
|
+
|
2037
|
+
Make sure to enable `config.render_views` in your
|
2038
|
+
`config/rails_helper.rb` or `config/spec_helper.rb` if you\'re using
|
2039
|
+
jbuilder, or you will get back empty results
|
2040
|
+
|
2041
|
+
# Bindings Generator
|
2042
|
+
|
2043
|
+
In earlier versions (\<= 0.0.13), there was a simple client generator as
|
2044
|
+
a part of Apipie gem. As more features and users came to Apipie, there
|
2045
|
+
was a greater need for changes on a per project basis. It\'s hard (or
|
2046
|
+
even impossible) to provide a generic solution for the client code. We
|
2047
|
+
also don\'t want to tell you what\'s the right way to do it (what gems
|
2048
|
+
to use, how the API should look like etc.).
|
2049
|
+
|
2050
|
+
Therefore you can\'t generate client code directly by a rake task in
|
2051
|
+
further versions.
|
2052
|
+
|
2053
|
+
There is, however, an even better and more flexible way to reuse your
|
2054
|
+
API documentation for this purpose: using the API the Apipie provides in
|
2055
|
+
the generator code. Check out our sister project
|
2056
|
+
[apipie-bindings](https://github.com/Apipie/apipie-bindings), as they
|
2057
|
+
use exactly this approach. You also don\'t need to run the service,
|
2058
|
+
provided it uses Apipie as a backend.
|
2059
|
+
|
2060
|
+
And if you write one on your own, don\'t hesitate to share it with us!
|
2061
|
+
|
2062
|
+
# Contributing
|
2063
|
+
|
2064
|
+
Then, you can install dependencies and run the test suite:
|
2065
|
+
|
2066
|
+
``` shell
|
2067
|
+
> bundle install
|
2068
|
+
> bundle exec rspec
|
2069
|
+
```
|
2070
|
+
|
2071
|
+
# Disqus Integration
|
2072
|
+
|
2073
|
+
You can setup [Disqus](https://disqus.com/) discussion within your
|
2074
|
+
documentation. Just set the credentials in the Apipie configuration:
|
2075
|
+
|
2076
|
+
``` ruby
|
2077
|
+
config.disqus_shortname = "MyProjectDoc"
|
2078
|
+
```
|
2079
|
+
|
2080
|
+
# External References
|
2081
|
+
|
2082
|
+
- [Getting started tutorial](https://github.com/iNecas/apipie-demo)
|
2083
|
+
-including examples of using the tests integration and versioning.
|
2084
|
+
- [Real-world application usage](https://github.com/Katello/katello)
|
2085
|
+
- [Read-world application usage with
|
2086
|
+
versioning](https://github.com/theforeman/foreman)
|
2087
|
+
- [Using Apipie API to generate
|
2088
|
+
bindings](https://github.com/Apipie/apipie-bindings)
|