apipie-rails 1.3.0 → 1.4.1

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