apipie-rails 0.3.6 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build.yml +67 -0
  3. data/.github/workflows/rubocop-challenger.yml +28 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +37 -0
  6. data/.rubocop_todo.yml +1991 -0
  7. data/CHANGELOG.md +246 -2
  8. data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
  9. data/README.rst +646 -25
  10. data/Rakefile +0 -5
  11. data/apipie-rails.gemspec +14 -9
  12. data/app/controllers/apipie/apipies_controller.rb +51 -20
  13. data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +70 -41
  14. data/app/public/apipie/javascripts/bundled/bootstrap.js +1033 -479
  15. data/app/public/apipie/javascripts/bundled/jquery.js +5 -5
  16. data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +9 -12
  17. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +9 -689
  18. data/app/views/apipie/apipies/_method_detail.erb +21 -0
  19. data/app/views/apipie/apipies/_params.html.erb +4 -2
  20. data/app/views/apipie/apipies/index.html.erb +5 -1
  21. data/app/views/apipie/apipies/resource.html.erb +3 -0
  22. data/app/views/layouts/apipie/apipie.html.erb +1 -1
  23. data/config/locales/en.yml +1 -0
  24. data/config/locales/fr.yml +31 -0
  25. data/config/locales/it.yml +31 -0
  26. data/config/locales/ja.yml +31 -0
  27. data/config/locales/ko.yml +31 -0
  28. data/config/locales/pt-BR.yml +1 -1
  29. data/gemfiles/Gemfile.rails50 +10 -0
  30. data/gemfiles/Gemfile.rails51 +10 -0
  31. data/gemfiles/Gemfile.rails52 +10 -0
  32. data/gemfiles/Gemfile.rails60 +17 -0
  33. data/gemfiles/Gemfile.rails61 +17 -0
  34. data/gemfiles/Gemfile.rails70 +17 -0
  35. data/lib/apipie/apipie_module.rb +22 -4
  36. data/lib/apipie/application.rb +54 -25
  37. data/lib/apipie/configuration.rb +26 -4
  38. data/lib/apipie/core_ext/route.rb +9 -0
  39. data/lib/apipie/dsl_definition.rb +168 -16
  40. data/lib/apipie/error_description.rb +9 -2
  41. data/lib/apipie/errors.rb +34 -0
  42. data/lib/apipie/extractor/collector.rb +4 -0
  43. data/lib/apipie/extractor/recorder.rb +14 -12
  44. data/lib/apipie/extractor/writer.rb +86 -58
  45. data/lib/apipie/extractor.rb +5 -5
  46. data/lib/apipie/generator/generator.rb +2 -0
  47. data/lib/apipie/generator/swagger/swagger.rb +2 -0
  48. data/lib/apipie/generator/swagger/type.rb +16 -0
  49. data/lib/apipie/generator/swagger/type_extractor.rb +70 -0
  50. data/lib/apipie/generator/swagger/warning.rb +77 -0
  51. data/lib/apipie/generator/swagger/warning_writer.rb +48 -0
  52. data/lib/apipie/markup.rb +14 -11
  53. data/lib/apipie/method_description/api.rb +12 -0
  54. data/lib/apipie/method_description/apis_service.rb +82 -0
  55. data/lib/apipie/method_description.rb +51 -49
  56. data/lib/apipie/param_description.rb +63 -5
  57. data/lib/apipie/resource_description.rb +11 -4
  58. data/lib/apipie/response_description.rb +131 -0
  59. data/lib/apipie/response_description_adapter.rb +200 -0
  60. data/lib/apipie/routes_formatter.rb +1 -1
  61. data/lib/apipie/rspec/response_validation_helper.rb +194 -0
  62. data/lib/apipie/static_dispatcher.rb +5 -2
  63. data/lib/apipie/swagger_generator.rb +717 -0
  64. data/lib/apipie/tag_list_description.rb +11 -0
  65. data/lib/apipie/validator.rb +83 -9
  66. data/lib/apipie/version.rb +1 -1
  67. data/lib/apipie-rails.rb +15 -4
  68. data/lib/generators/apipie/install/install_generator.rb +1 -1
  69. data/lib/generators/apipie/views_generator.rb +1 -1
  70. data/lib/tasks/apipie.rake +115 -15
  71. data/rel-eng/gem_release.ipynb +398 -0
  72. data/spec/controllers/apipies_controller_spec.rb +79 -14
  73. data/spec/controllers/concerns_controller_spec.rb +2 -2
  74. data/spec/controllers/extended_controller_spec.rb +14 -0
  75. data/spec/controllers/included_param_group_controller_spec.rb +13 -0
  76. data/spec/controllers/memes_controller_spec.rb +10 -0
  77. data/spec/controllers/users_controller_spec.rb +139 -76
  78. data/spec/dummy/Rakefile +1 -1
  79. data/spec/dummy/app/controllers/application_controller.rb +5 -1
  80. data/spec/dummy/app/controllers/concerns_controller.rb +1 -1
  81. data/spec/dummy/app/controllers/extended_controller.rb +14 -0
  82. data/spec/dummy/app/controllers/extending_concern.rb +10 -0
  83. data/spec/dummy/app/controllers/included_param_group_controller.rb +19 -0
  84. data/spec/dummy/app/controllers/overridden_concerns_controller.rb +2 -2
  85. data/spec/dummy/app/controllers/pets_controller.rb +408 -0
  86. data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
  87. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
  88. data/spec/dummy/app/controllers/{concerns/sample_controller.rb → sample_controller.rb} +5 -7
  89. data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
  90. data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
  91. data/spec/dummy/app/controllers/twitter_example_controller.rb +5 -0
  92. data/spec/dummy/app/controllers/users_controller.rb +26 -12
  93. data/spec/dummy/app/helpers/random_param_group.rb +8 -0
  94. data/spec/dummy/components/test_engine/Gemfile +6 -0
  95. data/spec/dummy/components/test_engine/app/controllers/test_engine/application_controller.rb +4 -0
  96. data/spec/dummy/components/test_engine/app/controllers/test_engine/memes_controller.rb +37 -0
  97. data/spec/dummy/components/test_engine/config/routes.rb +3 -0
  98. data/spec/dummy/components/test_engine/db/.gitkeep +0 -0
  99. data/spec/dummy/components/test_engine/lib/test_engine.rb +7 -0
  100. data/spec/dummy/components/test_engine/test_engine.gemspec +11 -0
  101. data/spec/dummy/config/application.rb +6 -4
  102. data/spec/dummy/config/boot.rb +2 -2
  103. data/spec/dummy/config/environment.rb +1 -1
  104. data/spec/dummy/config/environments/development.rb +3 -3
  105. data/spec/dummy/config/environments/production.rb +3 -3
  106. data/spec/dummy/config/environments/test.rb +3 -5
  107. data/spec/dummy/config/initializers/apipie.rb +5 -3
  108. data/spec/dummy/config/routes.rb +25 -1
  109. data/spec/dummy/config.ru +1 -1
  110. data/spec/dummy/script/rails +2 -2
  111. data/spec/lib/application_spec.rb +1 -1
  112. data/spec/lib/extractor/writer_spec.rb +37 -7
  113. data/spec/lib/file_handler_spec.rb +25 -0
  114. data/spec/lib/generator/swagger/type_extractor_spec.rb +61 -0
  115. data/spec/lib/generator/swagger/warning_spec.rb +51 -0
  116. data/spec/lib/generator/swagger/warning_writer_spec.rb +59 -0
  117. data/spec/lib/method_description/apis_service_spec.rb +60 -0
  118. data/spec/lib/method_description_spec.rb +34 -0
  119. data/spec/lib/param_description_spec.rb +90 -4
  120. data/spec/lib/rake_spec.rb +2 -4
  121. data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
  122. data/spec/lib/swagger/rake_swagger_spec.rb +154 -0
  123. data/spec/lib/swagger/response_validation_spec.rb +104 -0
  124. data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
  125. data/spec/lib/validator_spec.rb +59 -1
  126. data/spec/lib/validators/array_validator_spec.rb +28 -8
  127. data/spec/spec_helper.rb +49 -3
  128. data/spec/support/custom_bool_validator.rb +17 -0
  129. metadata +104 -99
  130. data/.travis.yml +0 -12
  131. data/Gemfile +0 -7
  132. data/Gemfile.rails32 +0 -6
  133. data/Gemfile.rails40 +0 -5
  134. data/Gemfile.rails41 +0 -5
  135. data/Gemfile.rails42 +0 -5
  136. data/lib/apipie/client/generator.rb +0 -135
data/README.rst CHANGED
@@ -2,9 +2,9 @@
2
2
  API Documentation Tool
3
3
  ========================
4
4
 
5
- .. image:: https://travis-ci.org/Apipie/apipie-rails.png?branch=master
6
- :target: https://travis-ci.org/Apipie/apipie-rails
7
- .. image:: https://codeclimate.com/github/Apipie/apipie-rails.png
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
8
  :target: https://codeclimate.com/github/Apipie/apipie-rails
9
9
  .. image:: https://badges.gitter.im/Apipie/apipie-rails.svg
10
10
  :alt: Join the chat at https://gitter.im/Apipie/apipie-rails
@@ -45,7 +45,7 @@ Now you can start documenting your resources and actions (see
45
45
  .. code:: ruby
46
46
 
47
47
  api :GET, '/users/:id'
48
- param :id, :number
48
+ param :id, :number, desc: 'id of the requested user'
49
49
  def show
50
50
  # ...
51
51
  end
@@ -117,6 +117,9 @@ desc (also description and full_description)
117
117
  param
118
118
  Common params for all methods defined in controller/child controllers.
119
119
 
120
+ returns
121
+ Common responses for all methods defined in controller/child controllers.
122
+
120
123
  api_base_url
121
124
  What URL is the resource available under.
122
125
 
@@ -136,6 +139,9 @@ app_info
136
139
  meta
137
140
  Hash or array with custom metadata.
138
141
 
142
+ deprecated
143
+ Boolean value indicating if the resource is marked as deprecated. (Default false)
144
+
139
145
  Example:
140
146
  ~~~~~~~~
141
147
 
@@ -144,7 +150,7 @@ Example:
144
150
  resource_description do
145
151
  short 'Site members'
146
152
  formats ['json']
147
- param :id, Fixnum, :desc => "User ID", :required => false
153
+ param :id, Integer, :desc => "User ID", :required => false
148
154
  param :resource_param, Hash, :desc => 'Param description for all methods' do
149
155
  param :ausername, String, :desc => "Username for login", :required => true
150
156
  param :apassword, String, :desc => "Password for login", :required => true
@@ -152,7 +158,12 @@ Example:
152
158
  api_version "development"
153
159
  error 404, "Missing"
154
160
  error 500, "Server crashed for some <%= reason %>", :meta => {:anything => "you can think of"}
161
+ error :unprocessable_entity, "Could not save the entity."
162
+ returns :code => 403 do
163
+ property :reason, String, :desc => "Why this was forbidden"
164
+ end
155
165
  meta :author => {:name => 'John', :surname => 'Doe'}
166
+ deprecated false
156
167
  description <<-EOS
157
168
  == Long description
158
169
  Example resource for rest api documentation
@@ -206,7 +217,16 @@ api_versions (also api_version)
206
217
  What version(s) does the action belong to. (See `Versioning`_ for details.)
207
218
 
208
219
  param
209
- Look at Parameter description section for details.
220
+ Look at `Parameter description`_ section for details.
221
+
222
+ returns
223
+ Look at `Response description`_ section for details.
224
+
225
+ tags
226
+ Adds tags for grouping operations together in Swagger outputs. See `swagger`_
227
+ for more details. You can also provide tags in the `Resource Description`_
228
+ block so that they are automatically prepended to all action tags in the
229
+ controller.
210
230
 
211
231
  formats
212
232
  Method level request / response formats.
@@ -256,6 +276,15 @@ Example:
256
276
  val == "param value" ? true : "The only good value is 'param value'."
257
277
  }, :desc => "proc validator"
258
278
  param :param_with_metadata, String, :desc => "", :meta => [:your, :custom, :metadata]
279
+ returns :code => 200, :desc => "a successful response" do
280
+ property :value1, String, :desc => "A string value"
281
+ property :value2, Integer, :desc => "An integer value"
282
+ property :value3, Hash, :desc => "An object" do
283
+ property :enum1, ['v1', 'v2'], :desc => "One of 2 possible string values"
284
+ end
285
+ end
286
+ tags %w[profiles logins]
287
+ tags 'more', 'related', 'resources'
259
288
  description "method description"
260
289
  formats ['json', 'jsonp', 'xml']
261
290
  meta :message => "Some very important info"
@@ -266,7 +295,6 @@ Example:
266
295
  #...
267
296
  end
268
297
 
269
-
270
298
  Parameter Description
271
299
  ---------------------
272
300
 
@@ -288,6 +316,9 @@ required
288
316
  allow_nil
289
317
  Setting this to true means that ``nil`` can be passed.
290
318
 
319
+ allow_blank
320
+ Like ``allow_nil``, but for blank values. ``false``, ``""``, ``' '``, ``nil``, ``[]``, and ``{}`` are all blank.
321
+
291
322
  as
292
323
  Used by the processing functionality to change the name of a key params.
293
324
 
@@ -301,6 +332,13 @@ missing_message
301
332
  Specify the message to be returned if the parameter is missing as a string or Proc.
302
333
  Defaults to ``Missing parameter #{name}`` if not specified.
303
334
 
335
+ only_in
336
+ This can be set to ``:request`` or ``:response``.
337
+ Setting to ``:response`` causes the param to be ignored when used as part of a request description.
338
+ Setting to ``:request`` causes this param to be ignored when used as part of a response description.
339
+ If ``only_in`` is not specified, the param definition is used for both requests and responses.
340
+ (Note that the keyword ``property`` is similar to ``param``, but it has a ``:only_in => :response`` default).
341
+
304
342
  Example:
305
343
  ~~~~~~~~
306
344
 
@@ -349,20 +387,20 @@ Example:
349
387
  end
350
388
  end
351
389
 
352
- api :POST, "/users", "Create an user"
390
+ api :POST, "/users", "Create a user"
353
391
  param_group :user
354
392
  def create
355
393
  # ...
356
394
  end
357
395
 
358
- api :PUT, "/users/:id", "Update an user"
396
+ api :PUT, "/users/:id", "Update a user"
359
397
  param_group :user
360
398
  def update
361
399
  # ...
362
400
  end
363
401
 
364
402
  # v2/users_controller.rb
365
- api :POST, "/users", "Create an user"
403
+ api :POST, "/users", "Create a user"
366
404
  param_group :user, V1::UsersController
367
405
  def create
368
406
  # ...
@@ -396,7 +434,7 @@ Example
396
434
  end
397
435
  end
398
436
 
399
- api :POST, "/users", "Create an user"
437
+ api :POST, "/users", "Create a user"
400
438
  param_group :user
401
439
  def create
402
440
  # ...
@@ -408,7 +446,7 @@ Example
408
446
  # ...
409
447
  end
410
448
 
411
- api :PUT, "/users/:id", "Update an user"
449
+ api :PUT, "/users/:id", "Update a user"
412
450
  param_group :user
413
451
  def update
414
452
  # ...
@@ -421,6 +459,291 @@ with ``allow_nil`` set explicitly don't have this value changed.
421
459
  Action awareness is inherited from ancestors (in terms of
422
460
  nested params).
423
461
 
462
+
463
+ Response Description
464
+ --------------------
465
+
466
+ The response from an API call can be documented by adding a ``returns`` statement to the method
467
+ description. This is especially useful when using Apipie to auto-generate a machine-readable Swagger
468
+ definition of your API (see the `swagger`_ section for more details).
469
+
470
+ A ``returns`` statement has several possible formats:
471
+
472
+ .. code:: ruby
473
+
474
+ # format #1: reference to a param-group
475
+ returns <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
476
+
477
+ # format #2: inline response definition
478
+ returns :code => <number>|<http-response-code-symbol> [, :desc => <human-readable description>] do
479
+ # property ...
480
+ # property ...
481
+ # param_group ...
482
+ end
483
+
484
+ # format #3: describing an array-of-objects response
485
+ returns :array_of => <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
486
+
487
+
488
+ If the ``:code`` argument is ommitted, ``200`` is used.
489
+
490
+
491
+ Example
492
+ ~~~~~~~
493
+
494
+ .. code:: ruby
495
+
496
+ # ------------------------------------------------
497
+ # Example of format #1 (reference to param-group):
498
+ # ------------------------------------------------
499
+ # the param_group :pet is defined here to describe the output returned by the method below.
500
+ def_param_group :pet do
501
+ property :pet_name, String, :desc => "Name of pet"
502
+ property :animal_type, ['dog','cat','iguana','kangaroo'], :desc => "Type of pet"
503
+ end
504
+
505
+ api :GET, "/pets/:id", "Get a pet record"
506
+ returns :pet, :desc => "The pet"
507
+ def show_detailed
508
+ render JSON({:pet_name => "Skippie", :animal_type => "kangaroo"})
509
+ end
510
+
511
+ # ------------------------------------------------
512
+ # Example of format #2 (inline):
513
+ # ------------------------------------------------
514
+ api :GET, "/pets/:id/with-extra-details", "Get a detailed pet record"
515
+ returns :code => 200, :desc => "Detailed info about the pet" do
516
+ param_group :pet
517
+ property :num_legs, Integer, :desc => "How many legs the pet has"
518
+ end
519
+ def show
520
+ render JSON({:pet_name => "Barkie", :animal_type => "iguana", :legs => 4})
521
+ end
522
+
523
+ # ------------------------------------------------
524
+ # Example of format #3 (array response):
525
+ # ------------------------------------------------
526
+ api :GET, "/pets", "Get all pet records"
527
+ returns :array_of => :pet, :code => 200, :desc => "All pets"
528
+ def index
529
+ render JSON([ {:pet_name => "Skippie", :animal_type => "kangaroo"},
530
+ {:pet_name => "Woofie", :animal_type => "cat"} ])
531
+ end
532
+
533
+
534
+ Note the use of the ``property`` keyword rather than ``param``. This is the
535
+ preferred mechanism for documenting response-only fields.
536
+
537
+
538
+ The Property keyword
539
+ ::::::::::::::::::::::::::::::::::::::::::::::::
540
+
541
+ ``property`` is very similar to ``param`` with the following differences:
542
+
543
+ * a ``property`` is ``:only_in => :response`` by default
544
+
545
+ * a ``property`` is ``:required => :true`` by default
546
+
547
+ * a ``property`` can be an ``:array_of`` objects
548
+
549
+ Example
550
+ _______
551
+ .. code:: ruby
552
+
553
+ property :example, :array_of => Hash do
554
+ property :number1, Integer
555
+ property :number2, Integer
556
+ end
557
+
558
+
559
+ Describing multiple return codes
560
+ ::::::::::::::::::::::::::::::::::::::::::::::::
561
+
562
+ To describe multiple possible return codes, the ``:returns`` keyword can be repeated as many times as necessary
563
+ (once for each return code). Each one of the ``:returns`` entries can specify a different response format.
564
+
565
+ Example
566
+ _______
567
+
568
+ .. code:: ruby
569
+
570
+ api :GET, "/pets/:id/extra_info", "Get extra information about a pet"
571
+ returns :desc => "Found a pet" do
572
+ param_group :pet
573
+ property 'pet_history', Hash do
574
+ param_group :pet_history
575
+ end
576
+ end
577
+ returns :code => :unprocessable_entity, :desc => "Fleas were discovered on the pet" do
578
+ param_group :pet
579
+ property :num_fleas, Integer, :desc => "Number of fleas on this pet"
580
+ end
581
+ def show_extra_info
582
+ # ... implementation here
583
+ end
584
+
585
+
586
+
587
+ Reusing a param_group to describe inputs and outputs
588
+ ::::::::::::::::::::::::::::::::::::::::::::::::::::
589
+
590
+ In many cases (such as CRUD implementations), the output from certain API calls is very similar - but not
591
+ identical - to the inputs of the same or other API calls.
592
+
593
+ If you already have a ``:param_group`` that defines the input to a `create` or `update` routine, it would be quite
594
+ frustrating to have to define a completely separate ``:param_group`` to describe the output of the `show` routine.
595
+
596
+ To address such situations, it is possible to define a single ``:param_group`` which combines ``param`` and ``property``
597
+ statements (as well as ``:only_in => :request`` / ``:only_in => :response``) to differentiate between fields that are
598
+ only expected in the request, only included in the response, or common to both.
599
+
600
+ This is somewhat analogous to the way `Action Aware params`_ work.
601
+
602
+ Example
603
+ _______
604
+
605
+ .. code:: ruby
606
+
607
+ def_param_group :user_record
608
+ param :name, String # this is commong to both the request and the response
609
+ param :force_update, [true, false], :only_in => :request # this does not show up in responses
610
+ property :last_login, String # this shows up only in the response
611
+ end
612
+
613
+ api :POST, "/users", "Create a user"
614
+ param_group :user_record # the :last_login field is not expected here, but :force_update is
615
+ def create
616
+ # ...
617
+ end
618
+
619
+ api :GET, "/users", "Create a user"
620
+ returns :array_of => :user_record # the :last_login field will be included in the response, but :force_update will not
621
+ def index
622
+ # ...
623
+ end
624
+
625
+
626
+ Embedded response descriptions
627
+ ::::::::::::::::::::::::::::::
628
+
629
+ If the code creating JSON responses is encapsulated within dedicated classes, it can be more convenient to
630
+ place the response descriptions outside of the controller and embed them within the response generator.
631
+
632
+ To support such use cases, Apipie allows any class to provide a `describe_own_properties` class method which
633
+ returns a description of the properties such a class would expose. It is then possible to specify that
634
+ class in the `returns` statement instead of a `param_group`.
635
+
636
+ The `describe_own_properties` method is expected to return an array of `Apipie::prop` objects, each one
637
+ describing a single property.
638
+
639
+ Example
640
+ _______
641
+
642
+ .. code:: ruby
643
+
644
+ class Pet
645
+ # this method is automatically called by Apipie when Pet is specified as the returned object type
646
+ def self.describe_own_properties
647
+ [
648
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
649
+ Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
650
+ Apipie::additional_properties(false) # this indicates that :pet_name and :animal_type are the only properties in the response
651
+ ]
652
+ end
653
+
654
+ # this method w
655
+ def json
656
+ JSON({:pet_name => @name, :animal_type => @type })
657
+ end
658
+ end
659
+
660
+
661
+ class PetsController
662
+ api :GET, "/index", "Get all pets"
663
+ returns :array_of => Pet # Pet is a 'self-describing-class'
664
+ def index
665
+ # ...
666
+ end
667
+ end
668
+
669
+
670
+ A use case where this is very useful is when JSON generation is done using a reflection mechanism or some
671
+ other sort of declarative mechanism.
672
+
673
+
674
+
675
+
676
+ The `Apipie::prop` function expects the following inputs:
677
+
678
+ .. code:: ruby
679
+
680
+ Apipie::prop(<property-name>, <property-type>, <options-hash> [, <array of sub-properties>])
681
+
682
+ # property-name should be a symbol
683
+ #
684
+ # property-type can be any of the following strings:
685
+ # "integer": maps to a swagger "integer" with an "int32" format
686
+ # "long": maps to a swagger "integer" with an "int64" format
687
+ # "number": maps to a swagger "number"(no format specifier)
688
+ # "float": maps to a swagger "number" with a "float" format
689
+ # "double": maps to a swagger "number" with a "double" format
690
+ # "string": maps to a swagger "string" (no format specifier)
691
+ # "byte": maps to a swagger "string" with a "byte" format
692
+ # "binary": maps to a swagger "string" with a "binary" format
693
+ # "boolean": maps to a swagger "boolean" (no format specifier)
694
+ # "date": maps to a swagger "string" with a "date" format
695
+ # "dateTime": maps to a swagger "string" with a "date-time" format
696
+ # "password": maps to a swagger "string" with a "password" format
697
+ # "object": the property has sub-properties. include <array of sub-properties> in the call.
698
+ # (see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more information
699
+ # about the mapped swagger types)
700
+ #
701
+ # options-hash can include any of the options fields allowed in a :returns statement.
702
+ # additionally, it can include the ':is_array => true', in which case the property is understood to be
703
+ # an array of the described type.
704
+
705
+
706
+
707
+ To describe an embedded object:
708
+
709
+ .. code:: ruby
710
+
711
+
712
+ #
713
+ # PetWithMeasurements is a self-describing class with an embedded object
714
+ #
715
+ class PetWithMeasurements
716
+ def self.describe_own_properties
717
+ [
718
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
719
+ Apipie::prop('animal_type', 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
720
+ Apipie::prop(:pet_measurements, 'object', {}, [
721
+ Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
722
+ Apipie::prop(:height, 'number', {:description => "Height in inches" }),
723
+ Apipie::prop(:num_legs, 'number', {:description => "Number of legs", :required => false }),
724
+ Apipie::additional_properties(false)
725
+ ])
726
+ ]
727
+ end
728
+ end
729
+
730
+ #
731
+ # PetWithManyMeasurements is a self-describing class with an embedded array of objects
732
+ #
733
+ class PetWithManyMeasurements
734
+ def self.describe_own_properties
735
+ [
736
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
737
+ Apipie::prop(:many_pet_measurements, 'object', {is_array: true}, [
738
+ Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
739
+ Apipie::prop(:height, 'number', {:description => "Height in inches" }),
740
+ ])
741
+ ]
742
+ end
743
+ end
744
+
745
+
746
+
424
747
  Concerns
425
748
  --------
426
749
 
@@ -500,6 +823,103 @@ Example
500
823
  end
501
824
 
502
825
 
826
+ Sometimes, it's needed to extend an existing controller method with additional
827
+ parameters (usually when extending exiting API from plugins/rails engines).
828
+ The concern can be also used for this purposed, using `update_api` method.
829
+ The params defined in this block are merged with the params of the original method
830
+ in the controller this concern is included to.
831
+
832
+ Example
833
+ ~~~~~~~
834
+
835
+ .. code:: ruby
836
+
837
+ module Concerns
838
+ module OauthConcern
839
+ extend Apipie::DSL::Concern
840
+
841
+ update_api(:create, :update) do
842
+ param :user, Hash do
843
+ param :oauth, String, :desc => 'oauth param'
844
+ end
845
+ end
846
+ end
847
+ end
848
+
849
+ The concern needs to be included to the controller after the methods are defined
850
+ (either at the end of the class, or by using
851
+ ``Controller.send(:include, Concerns::OauthConcern)``.
852
+
853
+
854
+ Response validation
855
+ -------------------
856
+
857
+ The swagger definitions created by Apipie can be used to auto-generate clients that access the
858
+ described APIs. Those clients will break if the responses returned from the API do not match
859
+ the declarations. As such, it is very important to include unit tests that validate the actual
860
+ responses against the swagger definitions.
861
+
862
+ The implemented mechanism provides two ways to include such validations in RSpec unit tests:
863
+ manual (using an RSpec matcher) and automated (by injecting a test into the http operations 'get', 'post',
864
+ raising an error if there is no match).
865
+
866
+ Example of the manual mechanism:
867
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
868
+
869
+ .. code:: ruby
870
+
871
+ require 'apipie/rspec/response_validation_helper'
872
+
873
+ RSpec.describe MyController, :type => :controller, :show_in_doc => true do
874
+
875
+ describe "GET stuff with response validation" do
876
+ render_views # this makes sure the 'get' operation will actually
877
+ # return the rendered view even though this is a Controller spec
878
+
879
+ it "does something" do
880
+ response = get :index, {format: :json}
881
+
882
+ # the following expectation will fail if the returned object
883
+ # does not match the 'returns' declaration in the Controller,
884
+ # or if there is no 'returns' declaration for the returned
885
+ # HTTP status code
886
+ expect(response).to match_declared_responses
887
+ end
888
+ end
889
+ end
890
+
891
+
892
+ Example of the automated mechanism:
893
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
894
+
895
+ .. code:: ruby
896
+
897
+ require 'apipie/rspec/response_validation_helper'
898
+
899
+ RSpec.describe MyController, :type => :controller, :show_in_doc => true do
900
+
901
+ describe "GET stuff with response validation" do
902
+ render_views
903
+ auto_validate_rendered_views
904
+
905
+ it "does something" do
906
+ get :index, {format: :json}
907
+ end
908
+ it "does something else" do
909
+ get :another_index, {format: :json}
910
+ end
911
+ end
912
+
913
+ describe "GET stuff without response validation" do
914
+ it "does something" do
915
+ get :index, {format: :json}
916
+ end
917
+ it "does something else" do
918
+ get :another_index, {format: :json}
919
+ end
920
+ end
921
+ end
922
+
503
923
 
504
924
  =========================
505
925
  Configuration Reference
@@ -516,6 +936,9 @@ app_name
516
936
  copyright
517
937
  Copyright information (shown in page footer).
518
938
 
939
+ compress_examples
940
+ If ``true`` recorded examples are compressed using ``Zlib``. Useful for big test-suits.
941
+
519
942
  doc_base_url
520
943
  Documentation frontend base url.
521
944
 
@@ -528,7 +951,7 @@ default_version
528
951
  validate
529
952
  Parameters validation is turned off when set to false. When set to
530
953
  ``:explicitly``, you must invoke parameter validation yourself by calling
531
- controller method ``apipie_validations`` (typically in a before_filter).
954
+ controller method ``apipie_validations`` (typically in a before_action).
532
955
  When set to ``:implicitly`` (or just true), your controller's action
533
956
  methods are wrapped with generated methods which call ``apipie_validations``,
534
957
  and then call the action method. (``:implicitly`` by default)
@@ -543,6 +966,9 @@ validate_presence
543
966
  validate_key
544
967
  Check the received params to ensure they are defined in the API. (false by default)
545
968
 
969
+ action_on_non_validated_keys
970
+ 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)
971
+
546
972
  process_params
547
973
  Process and extract the parameter defined from the params of the request
548
974
  to the api_params variable
@@ -598,6 +1024,10 @@ authorize
598
1024
  show_all_examples
599
1025
  Set this to true to set show_in_doc=1 in all recorded examples
600
1026
 
1027
+ ignore_allow_blank_false
1028
+ `allow_blank: false` was incorrectly ignored up until version 0.6.0, this bug was fixed in 0.7.0
1029
+ if you need the old behavior, set this to true
1030
+
601
1031
  link_extension
602
1032
  The extension to use for API pages ('.html' by default). Link extensions
603
1033
  in static API docs cannot be changed from '.html'.
@@ -726,17 +1156,32 @@ is raised and can be rescued and processed. It contains a description
726
1156
  of the parameter value expectations. Validations can be turned off
727
1157
  in the configuration file.
728
1158
 
729
- Parameter validation normally happens after before_filters, just before
1159
+ Here is an example of how to rescue and process a +ParamMissing+ or
1160
+ +ParamInvalid+ error from within the ApplicationController.
1161
+
1162
+ .. code:: ruby
1163
+
1164
+ class ApplicationController < ActionController::Base
1165
+
1166
+ # ParamError is superclass of ParamMissing, ParamInvalid
1167
+ rescue_from Apipie::ParamError do |e|
1168
+ render text: e.message, status: :unprocessable_entity
1169
+ end
1170
+
1171
+ # ...
1172
+ end
1173
+
1174
+ Parameter validation normally happens after before_actions, just before
730
1175
  your controller method is invoked. If you prefer to control when parameter
731
1176
  validation occurs, set the configuration parameter ``validate`` to ``:explicitly``.
732
1177
  You must then call the ``apipie_validations`` method yourself, e.g.:
733
1178
 
734
1179
  .. code:: ruby
735
1180
 
736
- before_filter: :apipie_validations
1181
+ before_action :apipie_validations
737
1182
 
738
- This is useful if you have before_filters which use parameter values: just add them
739
- after the ``apipie_validations`` before_filter.
1183
+ This is useful if you have before_actions which use parameter values: just add them
1184
+ after the ``apipie_validations`` before_action.
740
1185
 
741
1186
  TypeValidator
742
1187
  -------------
@@ -814,6 +1259,26 @@ override parameters described on the resource level.
814
1259
  #...
815
1260
  end
816
1261
 
1262
+ NumberValidator
1263
+ ---------------
1264
+
1265
+ Check if the parameter is a positive integer number or zero
1266
+
1267
+ .. code:: ruby
1268
+
1269
+ param :product_id, :number, :desc => "Identifier of the product", :required => true
1270
+ param :quantity, :number, :desc => "Number of products to order", :required => true
1271
+
1272
+ DecimalValidator
1273
+ --------------
1274
+
1275
+ Check if the parameter is a decimal number
1276
+
1277
+ .. code:: ruby
1278
+
1279
+ param :latitude, :decimal, :desc => "Geographic latitude", :required => true
1280
+ param :longitude, :decimal, :desc => "Geographic longitude", :required => true
1281
+
817
1282
  ArrayValidator
818
1283
  --------------
819
1284
 
@@ -910,7 +1375,7 @@ So we create apipie_validators.rb initializer with this content:
910
1375
  end
911
1376
 
912
1377
  def self.build(param_description, argument, options, block)
913
- if argument == Integer || argument == Fixnum
1378
+ if argument == Integer
914
1379
  self.new(param_description, argument)
915
1380
  end
916
1381
  end
@@ -918,6 +1383,10 @@ So we create apipie_validators.rb initializer with this content:
918
1383
  def description
919
1384
  "Must be #{@type}."
920
1385
  end
1386
+
1387
+ def expected_type
1388
+ 'numeric'
1389
+ end
921
1390
  end
922
1391
 
923
1392
  Parameters of the build method:
@@ -935,6 +1404,16 @@ options
935
1404
  block
936
1405
  Block converted into Proc, use it as you desire. In this example nil.
937
1406
 
1407
+ If your validator includes valid values that respond true to `.blank?`, you
1408
+ should also define:
1409
+
1410
+ .. code:: ruby
1411
+
1412
+ def ignore_allow_blank?
1413
+ true
1414
+ end
1415
+
1416
+ so that the validation does not fail for valid values.
938
1417
 
939
1418
  ============
940
1419
  Versioning
@@ -995,7 +1474,7 @@ the default version is used instead.
995
1474
  ========
996
1475
 
997
1476
  The default markup language is `RDoc
998
- <http://rdoc.rubyforge.org/RDoc/Markup.html>`_. It can be changed in
1477
+ <https://rdoc.github.io/rdoc/RDoc/Markup.html>`_. It can be changed in
999
1478
  the config file (``config.markup=``) to one of these:
1000
1479
 
1001
1480
  Markdown
@@ -1068,11 +1547,8 @@ When your project use I18n, localization related configuration could appear as f
1068
1547
  config.default_locale = 'en'
1069
1548
  config.locale = lambda { |loc| loc ? I18n.locale = loc : I18n.locale }
1070
1549
  config.translate = lambda do |str, loc|
1071
- old_loc = I18n.locale
1072
- I18n.locale = loc
1073
- trans = I18n.t(str)
1074
- I18n.locale = old_loc
1075
- trans
1550
+ return '' if str.blank?
1551
+ I18n.t str, locale: loc, scope: 'doc'
1076
1552
  end
1077
1553
  end
1078
1554
 
@@ -1123,6 +1599,137 @@ If, for some complex cases, you need to generate/re-generate just part of the ca
1123
1599
  use ``rake apipie:cache cache_part=index`` resp. ``rake apipie:cache cache_part=resources``
1124
1600
  To generate it for different locations for further processing use ``rake apipie:cache OUT=/tmp/apipie_cache``.
1125
1601
 
1602
+ .. _Swagger:
1603
+
1604
+ ====================================
1605
+ Static Swagger (OpenAPI 2.0) files
1606
+ ====================================
1607
+
1608
+ To generate a static Swagger definition file from the api, run ``rake apipie:static_swagger_json``.
1609
+ By default the documentation for the default API version is
1610
+ used. You can specify the version with ``rake apipie:static_swagger_json[2.0]``. A swagger file will be
1611
+ generated for each locale. The files will be generated in the same location as the static_json files, but
1612
+ instead of being named ``schema_apipie[.locale].json``, they will be called ``schema_swagger[.locale].json``.
1613
+
1614
+ Specifying default values for parameters
1615
+ -----------------------------------------
1616
+ Swagger allows method definitions to include an indication of the the default value for each parameter. To include such
1617
+ indications, use ``:default_value => <some value>`` in the parameter definition DSL. For example:
1618
+
1619
+ .. code:: ruby
1620
+
1621
+ param :do_something, Boolean, :desc => "take an action", :required => false, :default_value => false
1622
+
1623
+
1624
+ Generated Warnings
1625
+ -------------------
1626
+ The help identify potential improvements to your documentation, the swagger generation process issues warnings if
1627
+ it identifies various shortcomings of the DSL documentation. Each warning has a code to allow selective suppression
1628
+ (see swagger-specific configuration below)
1629
+
1630
+ :100: missing short description for method
1631
+ :101: added missing / at beginning of path
1632
+ :102: no return codes specified for method
1633
+ :103: a parameter is a generic Hash without an internal type specification
1634
+ :104: a parameter is an 'in-path' parameter, but specified as 'not required' in the DSL
1635
+ :105: a parameter is optional but does not have a default value specified
1636
+ :106: a parameter was ommitted from the swagger output because it is a Hash without fields in a formData specification
1637
+ :107: a path parameter is not described
1638
+ :108: inferring that a parameter type is boolean because described as an enum with [false,true] values
1639
+
1640
+
1641
+
1642
+ Swagger-Specific Configuration Parameters
1643
+ -------------------------------------------------
1644
+
1645
+ There are several configuration parameters that determine the structure of the generated swagger file:
1646
+
1647
+ ``config.swagger_content_type_input``
1648
+ If the value is ``:form_data`` - the swagger file will indicate that the server consumes the content types
1649
+ ``application/x-www-form-urlencoded`` and ``multipart/form-data``. Non-path parameters will have the
1650
+ value ``"in": "formData"``. Note that parameters of type Hash that do not have any fields in them will *be ommitted*
1651
+ from the resulting files, as there is no way to describe them in swagger.
1652
+
1653
+ If the value is ``:json`` - the swagger file will indicate that the server consumes the content type
1654
+ ``application/json``. All non-path parameters will be included in the schema of a single ``"in": "body"`` parameter
1655
+ of type ``object``.
1656
+
1657
+ You can specify the value of this configuration parameter as an additional input to the rake command (e.g.,
1658
+ ``rake apipie:static_swagger_json[2.0,form_data]``).
1659
+
1660
+ ``config.swagger_json_input_uses_refs``
1661
+ This parameter is only relevant if ``swagger_content_type_input`` is ``:json``.
1662
+
1663
+ If ``true``: the schema of the ``"in": "body"`` parameter of each method is given its own entry in the ``definitions``
1664
+ section, and is referenced using ``$ref`` from the method definition.
1665
+
1666
+ If ``false``: the body parameter definitions are inlined within the method definitions.
1667
+
1668
+ ``config.swagger_include_warning_tags``
1669
+ If ``true``: in addition to tagging methods with the name of the resource they belong to, methods for which warnings
1670
+ have been issued will be tagged with.
1671
+
1672
+ ``config.swagger_suppress_warnings``
1673
+ If ``false``: no warnings will be suppressed
1674
+
1675
+ If ``true``: all warnings will be suppressed
1676
+
1677
+ If an array of values (e.g., ``[100,102,107]``), only the warnings identified by the numbers in the array will be suppressed.
1678
+
1679
+ ``config.swagger_api_host``
1680
+ The value to place in the swagger host field.
1681
+
1682
+ Default is ``localhost:3000``
1683
+
1684
+ If ``nil`` then then host field will not be included.
1685
+
1686
+ ``config.swagger_allow_additional_properties_in_response``
1687
+ If ``false`` (default): response descriptions in the generated swagger will include an ``additional-properties: false``
1688
+ field
1689
+
1690
+ If ``true``: the ``additional-properties: false`` field will not be included in response object descriptions
1691
+
1692
+ ``config.swagger_schemes``
1693
+ An array of transport schemes that the API supports.
1694
+ This can include any combination of ``http``, ``https``, ``ws`` and ``wss``.
1695
+ By default to encourage good security practices, ``['https']`` is specified.
1696
+
1697
+
1698
+ ``config:swagger_security_definitions``
1699
+ If the API requires authentication, you can specify details of the authentication mechanisms supported as a (Hash) value here.
1700
+ See [https://swagger.io/docs/specification/2-0/authentication/] for details of what values can be specified
1701
+ By default, no security is defined.
1702
+
1703
+ ``config.swagger_global_security``
1704
+ 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.
1705
+ This should be used in conjunction with the mechanisms defined by ``swagger_security_definitions``.
1706
+ See [https://swagger.io/docs/specification/2-0/authentication/] for details of what values can be specified
1707
+ By default, no security is defined.
1708
+
1709
+
1710
+ Known limitations of the current implementation
1711
+ -------------------------------------------------
1712
+ * There is currently no way to document the structure and content-type of the data returned from a method
1713
+ * Recorded examples are currently not included in the generated swagger file
1714
+ * The apipie ``formats`` value is ignored.
1715
+ * It is not possible to specify the "consumed" content type on a per-method basis
1716
+ * It is not possible to leverage all of the parameter type/format capabilities of swagger
1717
+ * Only OpenAPI 2.0 is supported
1718
+ * Responses are defined inline and not as a $ref
1719
+ * It is not possible to specify per-operation security requirements (only global)
1720
+
1721
+ ====================================
1722
+ Dynamic Swagger generation
1723
+ ====================================
1724
+
1725
+ To generate swagger dynamically, use ``http://localhost:3000/apipie.json?type=swagger``.
1726
+
1727
+ Note that authorization is not supported for dynamic swagger generation, so if ``config.authorize`` is defined,
1728
+ dynamic swagger generation will be disabled.
1729
+
1730
+ Dynamically generated swagger is not cached, and is always generated on the fly.
1731
+
1732
+
1126
1733
  ===================
1127
1734
  JSON checksums
1128
1735
  ===================
@@ -1230,7 +1837,7 @@ one example per method) by adding a 'title' attribute.
1230
1837
  - recorded: true
1231
1838
 
1232
1839
  In RSpec you can add metadata to examples. We can use that feature
1233
- to mark selected examples the ones that perform the requests that we want to
1840
+ to mark selected examples - the ones that perform the requests that we want to
1234
1841
  show as examples in the documentation.
1235
1842
 
1236
1843
  For example, we can add ``show_in_doc`` to examples, like this:
@@ -1294,6 +1901,20 @@ provided it uses Apipie as a backend.
1294
1901
 
1295
1902
  And if you write one on your own, don't hesitate to share it with us!
1296
1903
 
1904
+ ====================
1905
+ Contributing
1906
+ ====================
1907
+
1908
+ Since this gem does not have a Gemfile, you need to specify it in your shell with:
1909
+
1910
+ .. code:: shell
1911
+ BUNDLE_GEMFILE='gemfiles/Gemfile.rails61'
1912
+
1913
+ Then, you can install dependencies and run the test suite:
1914
+
1915
+ .. code:: shell
1916
+ > bundle install
1917
+ > bundle exec rspec
1297
1918
 
1298
1919
  ====================
1299
1920
  Disqus Integration