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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +4 -3
  3. data/.github/workflows/rubocop-challenger.yml +1 -3
  4. data/.github/workflows/rubocop.yml +1 -1
  5. data/CHANGELOG.md +13 -0
  6. data/Gemfile +2 -3
  7. data/README.md +2088 -0
  8. data/apipie-rails.gemspec +7 -1
  9. data/app/views/apipie/apipies/_method_detail.erb +2 -0
  10. data/app/views/apipie/apipies/_params.html.erb +1 -0
  11. data/app/views/apipie/apipies/_params_plain.html.erb +1 -0
  12. data/config/locales/en.yml +1 -0
  13. data/config/locales/ko.yml +1 -0
  14. data/lib/apipie/application.rb +1 -1
  15. data/lib/apipie/dsl_definition.rb +3 -3
  16. data/lib/apipie/extractor/writer.rb +1 -1
  17. data/lib/apipie/generator/swagger/method_description/response_service.rb +14 -1
  18. data/lib/apipie/param_description.rb +1 -1
  19. data/lib/apipie/response_description.rb +34 -9
  20. data/lib/apipie/response_description_adapter.rb +1 -1
  21. data/lib/apipie/routes_formatter.rb +1 -1
  22. data/lib/apipie/version.rb +1 -1
  23. data/rel-eng/gem_release.ipynb +5 -5
  24. data/spec/controllers/users_controller_spec.rb +1 -1
  25. data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +1 -1
  26. data/spec/dummy/app/controllers/pets_controller.rb +1 -1
  27. data/spec/dummy/app/controllers/twitter_example_controller.rb +3 -3
  28. data/spec/lib/apipie/apipies_controller_spec.rb +1 -1
  29. data/spec/lib/apipie/file_handler_spec.rb +1 -1
  30. data/spec/lib/apipie/generator/swagger/method_description/response_service_spec.rb +62 -0
  31. data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +2 -2
  32. data/spec/lib/apipie/param_description_spec.rb +1 -1
  33. data/spec/lib/apipie/response_description/response_object_spec.rb +22 -0
  34. data/spec/lib/apipie/response_description_spec.rb +56 -0
  35. data/spec/lib/swagger/swagger_dsl_spec.rb +1 -1
  36. metadata +12 -6
  37. 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 = "&copy; 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)