apipierails3 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +17 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +27 -0
- data/APACHE-LICENSE-2.0 +202 -0
- data/CHANGELOG.md +469 -0
- data/Gemfile +1 -0
- data/Gemfile.rails32 +6 -0
- data/Gemfile.rails41 +6 -0
- data/Gemfile.rails42 +11 -0
- data/Gemfile.rails50 +6 -0
- data/Gemfile.rails51 +7 -0
- data/MIT-LICENSE +20 -0
- data/NOTICE +4 -0
- data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
- data/README.rst +1874 -0
- data/Rakefile +13 -0
- data/apipierails3.gemspec +27 -0
- data/app/controllers/apipie/apipies_controller.rb +199 -0
- data/app/helpers/apipie_helper.rb +10 -0
- data/app/public/apipie/javascripts/apipie.js +6 -0
- data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +138 -0
- data/app/public/apipie/javascripts/bundled/bootstrap.js +1726 -0
- data/app/public/apipie/javascripts/bundled/jquery.js +5 -0
- data/app/public/apipie/javascripts/bundled/prettify.js +28 -0
- data/app/public/apipie/stylesheets/application.css +7 -0
- data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +12 -0
- data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +689 -0
- data/app/public/apipie/stylesheets/bundled/prettify.css +30 -0
- data/app/views/apipie/apipies/_disqus.html.erb +13 -0
- data/app/views/apipie/apipies/_errors.html.erb +23 -0
- data/app/views/apipie/apipies/_headers.html.erb +26 -0
- data/app/views/apipie/apipies/_languages.erb +6 -0
- data/app/views/apipie/apipies/_metadata.erb +1 -0
- data/app/views/apipie/apipies/_method_detail.erb +61 -0
- data/app/views/apipie/apipies/_params.html.erb +42 -0
- data/app/views/apipie/apipies/_params_plain.html.erb +20 -0
- data/app/views/apipie/apipies/apipie_404.html.erb +17 -0
- data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
- data/app/views/apipie/apipies/getting_started.html.erb +6 -0
- data/app/views/apipie/apipies/index.html.erb +56 -0
- data/app/views/apipie/apipies/method.html.erb +41 -0
- data/app/views/apipie/apipies/plain.html.erb +77 -0
- data/app/views/apipie/apipies/resource.html.erb +80 -0
- data/app/views/apipie/apipies/static.html.erb +103 -0
- data/app/views/layouts/apipie/apipie.html.erb +27 -0
- data/config/locales/de.yml +28 -0
- data/config/locales/en.yml +32 -0
- data/config/locales/es.yml +28 -0
- data/config/locales/fr.yml +31 -0
- data/config/locales/it.yml +31 -0
- data/config/locales/ja.yml +31 -0
- data/config/locales/pl.yml +28 -0
- data/config/locales/pt-BR.yml +28 -0
- data/config/locales/ru.yml +28 -0
- data/config/locales/tr.yml +28 -0
- data/config/locales/zh-CN.yml +28 -0
- data/config/locales/zh-TW.yml +28 -0
- data/images/screenshot-1.png +0 -0
- data/images/screenshot-2.png +0 -0
- data/lib/apipie/apipie_module.rb +83 -0
- data/lib/apipie/application.rb +462 -0
- data/lib/apipie/configuration.rb +186 -0
- data/lib/apipie/dsl_definition.rb +607 -0
- data/lib/apipie/error_description.rb +44 -0
- data/lib/apipie/errors.rb +86 -0
- data/lib/apipie/extractor.rb +177 -0
- data/lib/apipie/extractor/collector.rb +117 -0
- data/lib/apipie/extractor/recorder.rb +166 -0
- data/lib/apipie/extractor/writer.rb +454 -0
- data/lib/apipie/helpers.rb +73 -0
- data/lib/apipie/markup.rb +48 -0
- data/lib/apipie/method_description.rb +273 -0
- data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
- data/lib/apipie/param_description.rb +280 -0
- data/lib/apipie/railtie.rb +9 -0
- data/lib/apipie/resource_description.rb +124 -0
- data/lib/apipie/response_description.rb +131 -0
- data/lib/apipie/response_description_adapter.rb +200 -0
- data/lib/apipie/routes_formatter.rb +33 -0
- data/lib/apipie/routing.rb +16 -0
- data/lib/apipie/rspec/response_validation_helper.rb +192 -0
- data/lib/apipie/see_description.rb +39 -0
- data/lib/apipie/static_dispatcher.rb +69 -0
- data/lib/apipie/swagger_generator.rb +707 -0
- data/lib/apipie/tag_list_description.rb +11 -0
- data/lib/apipie/validator.rb +526 -0
- data/lib/apipie/version.rb +3 -0
- data/lib/apipierails3.rb +25 -0
- data/lib/generators/apipie/install/README +6 -0
- data/lib/generators/apipie/install/install_generator.rb +25 -0
- data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
- data/lib/generators/apipie/views_generator.rb +11 -0
- data/lib/tasks/apipie.rake +345 -0
- data/rel-eng/packages/.readme +3 -0
- data/rel-eng/packages/rubygem-apipie-rails +1 -0
- data/rel-eng/tito.props +5 -0
- data/spec/controllers/api/v1/architectures_controller_spec.rb +29 -0
- data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
- data/spec/controllers/api/v2/nested/resources_controller_spec.rb +11 -0
- data/spec/controllers/apipies_controller_spec.rb +273 -0
- data/spec/controllers/concerns_controller_spec.rb +42 -0
- data/spec/controllers/extended_controller_spec.rb +11 -0
- data/spec/controllers/users_controller_spec.rb +740 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
- data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +43 -0
- data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +30 -0
- data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +32 -0
- data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +33 -0
- data/spec/dummy/app/controllers/application_controller.rb +18 -0
- data/spec/dummy/app/controllers/concerns/extending_concern.rb +11 -0
- data/spec/dummy/app/controllers/concerns/sample_controller.rb +41 -0
- data/spec/dummy/app/controllers/concerns_controller.rb +8 -0
- data/spec/dummy/app/controllers/extended_controller.rb +14 -0
- data/spec/dummy/app/controllers/files_controller.rb +5 -0
- data/spec/dummy/app/controllers/overridden_concerns_controller.rb +31 -0
- data/spec/dummy/app/controllers/pets_controller.rb +408 -0
- data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
- data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
- data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
- data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
- data/spec/dummy/app/controllers/twitter_example_controller.rb +307 -0
- data/spec/dummy/app/controllers/users_controller.rb +297 -0
- data/spec/dummy/app/views/layouts/application.html.erb +21 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +49 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +21 -0
- data/spec/dummy/config/environment.rb +8 -0
- data/spec/dummy/config/environments/development.rb +28 -0
- data/spec/dummy/config/environments/production.rb +52 -0
- data/spec/dummy/config/environments/test.rb +38 -0
- data/spec/dummy/config/initializers/apipie.rb +110 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +51 -0
- data/spec/dummy/db/.gitkeep +0 -0
- data/spec/dummy/doc/apipie_examples.json +1 -0
- data/spec/dummy/doc/users/desc_from_file.md +1 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/application_spec.rb +49 -0
- data/spec/lib/extractor/extractor_spec.rb +9 -0
- data/spec/lib/extractor/middleware_spec.rb +44 -0
- data/spec/lib/extractor/writer_spec.rb +110 -0
- data/spec/lib/file_handler_spec.rb +18 -0
- data/spec/lib/method_description_spec.rb +98 -0
- data/spec/lib/param_description_spec.rb +345 -0
- data/spec/lib/param_group_spec.rb +60 -0
- data/spec/lib/rake_spec.rb +71 -0
- data/spec/lib/resource_description_spec.rb +48 -0
- data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
- data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
- data/spec/lib/swagger/response_validation_spec.rb +104 -0
- data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
- data/spec/lib/validator_spec.rb +113 -0
- data/spec/lib/validators/array_validator_spec.rb +85 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/support/rake.rb +21 -0
- metadata +415 -0
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
./Gemfile.rails50
|
data/Gemfile.rails32
ADDED
data/Gemfile.rails41
ADDED
data/Gemfile.rails42
ADDED
data/Gemfile.rails50
ADDED
data/Gemfile.rails51
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Pavel Pokorný
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/NOTICE
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
# Proposal for supporting response descriptions in Apipie
|
2
|
+
|
3
|
+
## Rationale
|
4
|
+
|
5
|
+
Swagger allows API authors to describe the structure of objects returned by REST API calls.
|
6
|
+
Client authors and code generators can use such descriptions for various purposes, such as verification,
|
7
|
+
autocompletion, and so forth.
|
8
|
+
|
9
|
+
The current Apipie DSL allows API authors to indicate returned error codes (using the `error` keyword),
|
10
|
+
but does not support descriptions of returned data objects. As such, swagger files
|
11
|
+
generated from the DSL do not include those, and are somewhat limited in their value.
|
12
|
+
|
13
|
+
This document proposes a minimalistic approach to extending the Apipie DSL to allow description of response
|
14
|
+
objects, and including those descriptions in generated swagger files.
|
15
|
+
|
16
|
+
## Design Objectives
|
17
|
+
|
18
|
+
* Full backward compatibility with the existing DSL
|
19
|
+
* Minimal implementation effort
|
20
|
+
* Enough expressiveness to support common use cases
|
21
|
+
* Optional integration of the DSL with advanced JSON generators (such as Grape-Entity)
|
22
|
+
* Allowing developers to easily verify that actual responses match the response declarations
|
23
|
+
|
24
|
+
## Approach
|
25
|
+
|
26
|
+
#### Add a `returns` keyword to the DSL, based on the existing `error` keyword
|
27
|
+
|
28
|
+
Currently, returned error codes are indicated using the `error` keyword, for example:
|
29
|
+
```ruby
|
30
|
+
api :GET, "/users/:id", "Show user profile"
|
31
|
+
error :code => 401, :desc => "Unauthorized"
|
32
|
+
```
|
33
|
+
|
34
|
+
The proposed approach is to add a `returns` keyword, that has the following syntax:
|
35
|
+
```ruby
|
36
|
+
returns <type-identifier> [, :code => <number>] [, :desc => <response-description>]
|
37
|
+
```
|
38
|
+
|
39
|
+
For example:
|
40
|
+
```ruby
|
41
|
+
api :GET, "/users/:id", "Show user profile"
|
42
|
+
error :code => 401, :desc => "Unauthorized"
|
43
|
+
returns :SomeTypeIdentifier # :code is not specified, so it is assumed to be 200
|
44
|
+
```
|
45
|
+
|
46
|
+
|
47
|
+
#### Leverage `param_group` for response object description
|
48
|
+
|
49
|
+
Apipie currently has a mechanism for describing complex objects using the `param_group` keyword.
|
50
|
+
It seems reasonable to leverage this mechanism as the basis of the response object description mechanism,
|
51
|
+
so that the `<type-identifier>` in the `returns` keyword will be the name of a param_group.
|
52
|
+
|
53
|
+
For example:
|
54
|
+
```ruby
|
55
|
+
def_param_group :user do
|
56
|
+
param :user, Hash, :desc => "User info", :required => true, :action_aware => true do
|
57
|
+
param_group :credentials
|
58
|
+
param :membership, ["standard","premium"], :desc => "User membership", :allow_nil => false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
api :GET, "/users/:id", "Get user record"
|
63
|
+
returns :user, "the requested record"
|
64
|
+
error :code => 404, :desc => "no user with the specified id"
|
65
|
+
```
|
66
|
+
|
67
|
+
Implementation of this DSL extension would involve - as part of the implementation of the `returns` keyword -
|
68
|
+
the generation of a Apipie::ParamDescription object that has a Hash validator pointing to the param_group block.
|
69
|
+
|
70
|
+
#### Extend action-aware functionality to include 'response-only' parameters
|
71
|
+
|
72
|
+
In CRUD operations, it is common for `param_group` input definitions to be very similar to the
|
73
|
+
output of the API, with the exception of a very small number of fields (such as the `:id` field
|
74
|
+
which usually appears in the response, but is not described in the `param_group` because it is passed as a
|
75
|
+
path parameter).
|
76
|
+
|
77
|
+
To allow reuse of the `param_group`, it would be useful to its definition to describe parameters that are not passed
|
78
|
+
in the request but are returned in the response. This would be implementing by extending the DSL to
|
79
|
+
support a `:only_in => :response` option on `param` definitions. Similarly, params could be defined to be
|
80
|
+
`:only_in => :request` to indicate that they will not be included in the response.
|
81
|
+
|
82
|
+
For example:
|
83
|
+
```ruby
|
84
|
+
# in the following group, the :id param is ignored in requests, but included in responses
|
85
|
+
def_param_group :user do
|
86
|
+
param :user, Hash, :desc => "User info", :required => true, :action_aware => true do
|
87
|
+
param :id, Integer, :only_in => :response
|
88
|
+
param :requested_id, Integer, :only_in => :request
|
89
|
+
param_group :credentials
|
90
|
+
param :membership, ["standard","premium"], :desc => "User membership", :allow_nil => false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
api :GET, "/users/:id", "Get user record"
|
95
|
+
returns :user, :desc => "the requested record" # includes the :id field, because this is a response
|
96
|
+
error :code => 404, :desc => "no user with the specified id"
|
97
|
+
```
|
98
|
+
|
99
|
+
|
100
|
+
#### Support `:array_of => <param_group-name>` in the `returns` keyword
|
101
|
+
|
102
|
+
Very often, a REST API call returns an array of some previously-defined object
|
103
|
+
(the most common example an `index` operation that returns an array of the same entity returned by a `show` request),
|
104
|
+
and it would be tedious to have to define a separate `param_group` for each one.
|
105
|
+
|
106
|
+
For added convenience, the `returns` keyword will also support an `:array_of =>` construct
|
107
|
+
to specify that an API call returns an array of some object type.
|
108
|
+
|
109
|
+
For example:
|
110
|
+
```ruby
|
111
|
+
api :GET, "/users", "Get all user records"
|
112
|
+
returns :array_of => :user, :desc => "the requested user records"
|
113
|
+
|
114
|
+
api :GET, "/user/:id", "Get a single user record"
|
115
|
+
returns :user, :desc => "the requested user record"
|
116
|
+
```
|
117
|
+
|
118
|
+
#### Integration with advanced JSON generators using an [adapter](https://en.wikipedia.org/wiki/Adapter_pattern) to `param_group`
|
119
|
+
|
120
|
+
While it makes sense for the sake of simplicity to leverage the `param_group` construct to describe
|
121
|
+
returned objects, it is likely that many developers will prefer to unify the
|
122
|
+
description of the response with the actual generation of the JSON.
|
123
|
+
|
124
|
+
Some JSON-generation libraries, such as [Grape-Entity](https://github.com/ruby-grape/grape-entity),
|
125
|
+
provide a declarative interface for describing an object model, allowing both runtime
|
126
|
+
generation of the response, as well as the ability to traverse the description to auto-generate
|
127
|
+
documentation.
|
128
|
+
|
129
|
+
Such libraries could be integrated with Apipie using adapters that wrap the library-specific
|
130
|
+
object description and expose an API that includes a `params_ordered` method that behaves in a
|
131
|
+
similar manner to [`Apipie::HashValidator.params_ordered`](https://github.com/Apipie/apipie-rails/blob/cfb42198bc39b5b30d953ba5a8b523bafdb4f897/lib/apipie/validator.rb#L315).
|
132
|
+
Such an adapter would make it possible to pass an externally-defined entity to the `returns` keyword
|
133
|
+
as if it were a `param_group`.
|
134
|
+
|
135
|
+
Such adapters can be created easily by having a class respond to `#describe_own_properties`
|
136
|
+
with an array of property description objects. When such a class is specified as the
|
137
|
+
parameter to a `returns` declaration, Apipie would query the class for its properties
|
138
|
+
by calling `<Class>#describe_own_properties`.
|
139
|
+
|
140
|
+
For example:
|
141
|
+
```ruby
|
142
|
+
# here is a class that can describe itself to Apipie
|
143
|
+
class Animal
|
144
|
+
def self.describe_own_properties
|
145
|
+
[
|
146
|
+
Apipie::prop(:id, Integer, {:description => 'Name of pet', :required => false}),
|
147
|
+
Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
|
148
|
+
Apipie::additional_properties(false)
|
149
|
+
]
|
150
|
+
end
|
151
|
+
|
152
|
+
attr_accessor :id
|
153
|
+
attr_accessor :animal_type
|
154
|
+
end
|
155
|
+
|
156
|
+
# Here is an API defined as returning Animal objects.
|
157
|
+
# Apipie creates an internal adapter by querying Animal#describe_own_properties
|
158
|
+
api :GET, "/animals", "Get all records"
|
159
|
+
returns :array_of => Animal, :desc => "the requested records"
|
160
|
+
```
|
161
|
+
|
162
|
+
The `#describe_own_properties` mechanism can also be used with reflection so that a
|
163
|
+
class would query its own properties and populate the response to `#describe_own_properties`
|
164
|
+
automatically. See [this gist](https://gist.github.com/elasti-ron/ac145b2c85547487ca33e5216a69f527)
|
165
|
+
for an example of how Grape::Entity classes can automatically describe itself to Apipie
|
166
|
+
|
167
|
+
#### Response validation
|
168
|
+
|
169
|
+
The swagger definitions created by Apipie can be used to auto-generate clients that access the
|
170
|
+
described APIs. Those clients will break if the responses returned from the API do not match
|
171
|
+
the declarations. As such, it is very important to include unit tests that validate the actual
|
172
|
+
responses against the swagger definitions.
|
173
|
+
|
174
|
+
The ~~proposed~~ implemented mechanism provides two ways to include such validations in RSpec unit tests:
|
175
|
+
manual (using an RSpec matcher) and automated (by injecting a test into the http operations 'get', 'post',
|
176
|
+
raising an error if there is no match).
|
177
|
+
|
178
|
+
Example of the manual mechanism:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
require 'apipie/rspec/response_validation_helper'
|
182
|
+
|
183
|
+
RSpec.describe MyController, :type => :controller, :show_in_doc => true do
|
184
|
+
|
185
|
+
describe "GET stuff with response validation" do
|
186
|
+
render_views # this makes sure the 'get' operation will actually
|
187
|
+
# return the rendered view even though this is a Controller spec
|
188
|
+
|
189
|
+
it "does something" do
|
190
|
+
response = get :index, {format: :json}
|
191
|
+
|
192
|
+
# the following expectation will fail if the returned object
|
193
|
+
# does not match the 'returns' declaration in the Controller,
|
194
|
+
# or if there is no 'returns' declaration for the returned
|
195
|
+
# HTTP status code
|
196
|
+
expect(response).to match_declared_responses
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
|
202
|
+
Example of the automated mechanism:
|
203
|
+
```ruby
|
204
|
+
require 'apipie/rspec/response_validation_helper'
|
205
|
+
|
206
|
+
RSpec.describe MyController, :type => :controller, :show_in_doc => true do
|
207
|
+
|
208
|
+
describe "GET stuff with response validation" do
|
209
|
+
render_views
|
210
|
+
auto_validate_rendered_views
|
211
|
+
|
212
|
+
it "does something" do
|
213
|
+
get :index, {format: :json}
|
214
|
+
end
|
215
|
+
it "does something else" do
|
216
|
+
get :another_index, {format: :json}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "GET stuff without response validation" do
|
221
|
+
it "does something" do
|
222
|
+
get :index, {format: :json}
|
223
|
+
end
|
224
|
+
it "does something else" do
|
225
|
+
get :another_index, {format: :json}
|
226
|
+
end
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
Explanation of the implementation approach:
|
231
|
+
|
232
|
+
The Apipie Swagger Generator is enhanced to allow extraction of the JSON schema of the response object
|
233
|
+
for any controller#action[http-status]. When validation is required, the validator receives the
|
234
|
+
actual response object (along with information about the controller, action and http status code),
|
235
|
+
queries the swagger generator to get the schema, and uses the json-schema validator (gem) to validate
|
236
|
+
one against the other.
|
237
|
+
|
238
|
+
Note that there is a slight complication here: while supported by JSON-shema, the Swagger 2.0
|
239
|
+
specification does not support a mechanism to declare that fields in the response could be null.
|
240
|
+
As such, for a response that contains `null` fields, if the exact same schema used in the swagger def
|
241
|
+
is passed to the json-schema validator, the validation fails. To work around this issue, when asked
|
242
|
+
to provide the schema for the purpose of response validation (i.e., not for inclusion in the swagger),
|
243
|
+
the Apipie Swagger Generator creates a slightly modified schema which declares null values to be valid.
|
244
|
+
|
data/README.rst
ADDED
@@ -0,0 +1,1874 @@
|
|
1
|
+
========================
|
2
|
+
API Documentation Tool
|
3
|
+
========================
|
4
|
+
|
5
|
+
.. image:: https://travis-ci.org/Apipie/apipie-rails.svg?branch=master
|
6
|
+
:target: https://travis-ci.org/Apipie/apipie-rails
|
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 'apipierails3'" >> 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/iNecas/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 <http://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
|
+
short (also short_description)
|
112
|
+
Short description of the resource (it's shown on both the list of resources, and resource details)
|
113
|
+
|
114
|
+
desc (also description and full_description)
|
115
|
+
Full description of the resource (shown only in resource details)
|
116
|
+
|
117
|
+
param
|
118
|
+
Common params for all methods defined in controller/child controllers.
|
119
|
+
|
120
|
+
returns
|
121
|
+
Common responses for all methods defined in controller/child controllers.
|
122
|
+
|
123
|
+
api_base_url
|
124
|
+
What URL is the resource available under.
|
125
|
+
|
126
|
+
api_versions (also api_version)
|
127
|
+
What versions does the controller define the resource. (See `Versioning`_ for details.)
|
128
|
+
|
129
|
+
formats
|
130
|
+
Request / response formats.
|
131
|
+
|
132
|
+
error
|
133
|
+
Describe every possible error that can happen when calling all
|
134
|
+
methods defined in controller. HTTP response code and description can be provided.
|
135
|
+
|
136
|
+
app_info
|
137
|
+
In case of versioning, this sets app info description on a per_version basis.
|
138
|
+
|
139
|
+
meta
|
140
|
+
Hash or array with custom metadata.
|
141
|
+
|
142
|
+
deprecated
|
143
|
+
Boolean value indicating if the resource is marked as deprecated. (Default false)
|
144
|
+
|
145
|
+
Example:
|
146
|
+
~~~~~~~~
|
147
|
+
|
148
|
+
.. code:: ruby
|
149
|
+
|
150
|
+
resource_description do
|
151
|
+
short 'Site members'
|
152
|
+
formats ['json']
|
153
|
+
param :id, Fixnum, :desc => "User ID", :required => false
|
154
|
+
param :resource_param, Hash, :desc => 'Param description for all methods' do
|
155
|
+
param :ausername, String, :desc => "Username for login", :required => true
|
156
|
+
param :apassword, String, :desc => "Password for login", :required => true
|
157
|
+
end
|
158
|
+
api_version "development"
|
159
|
+
error 404, "Missing"
|
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
|
165
|
+
meta :author => {:name => 'John', :surname => 'Doe'}
|
166
|
+
deprecated false
|
167
|
+
description <<-EOS
|
168
|
+
== Long description
|
169
|
+
Example resource for rest api documentation
|
170
|
+
These can now be accessed in <tt>shared/header</tt> with:
|
171
|
+
Headline: <%= headline %>
|
172
|
+
First name: <%= person.first_name %>
|
173
|
+
|
174
|
+
If you need to find out whether a certain local variable has been
|
175
|
+
assigned a value in a particular render call, you need to use the
|
176
|
+
following pattern:
|
177
|
+
|
178
|
+
<% if local_assigns.has_key? :headline %>
|
179
|
+
Headline: <%= headline %>
|
180
|
+
<% end %>
|
181
|
+
|
182
|
+
Testing using <tt>defined? headline</tt> will not work. This is an
|
183
|
+
implementation restriction.
|
184
|
+
|
185
|
+
=== Template caching
|
186
|
+
|
187
|
+
By default, Rails will compile each template to a method in order
|
188
|
+
to render it. When you alter a template, Rails will check the
|
189
|
+
file's modification time and recompile it in development mode.
|
190
|
+
EOS
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
Method Description
|
195
|
+
------------------
|
196
|
+
|
197
|
+
Then describe methods available to your API.
|
198
|
+
|
199
|
+
api
|
200
|
+
Describe how this method is exposed, and provide a short description.
|
201
|
+
The first parameter is HTTP method (one of :GET/:POST/:PUT/:DELETE).
|
202
|
+
The second parameter is the relative URL path which is mapped to this
|
203
|
+
method. The last parameter is the methods short description.
|
204
|
+
You can use this +api+ method more than once per method. It could
|
205
|
+
be useful when there are more routes mapped to it.
|
206
|
+
|
207
|
+
When providing just one argument (description), or no argument at all,
|
208
|
+
the paths will be loaded from the routes.rb file.
|
209
|
+
|
210
|
+
api!
|
211
|
+
Provide a short description and additional option.
|
212
|
+
The last parameter is the methods short description.
|
213
|
+
The paths will be loaded from routes.rb file. See
|
214
|
+
`Rails Routes Integration`_ for more details.
|
215
|
+
|
216
|
+
api_versions (also api_version)
|
217
|
+
What version(s) does the action belong to. (See `Versioning`_ for details.)
|
218
|
+
|
219
|
+
param
|
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.
|
230
|
+
|
231
|
+
formats
|
232
|
+
Method level request / response formats.
|
233
|
+
|
234
|
+
error
|
235
|
+
Describe each possible error that can happen while calling this
|
236
|
+
method. HTTP response code and description can be provided.
|
237
|
+
|
238
|
+
description
|
239
|
+
Full method description, which will be converted into HTML by the
|
240
|
+
chosen markup language processor.
|
241
|
+
|
242
|
+
example
|
243
|
+
Provide an example of the server response; whole communication or response type.
|
244
|
+
It will be formatted as code.
|
245
|
+
|
246
|
+
see
|
247
|
+
Provide reference to another method, this has to be a string with
|
248
|
+
controller_name#method_name.
|
249
|
+
|
250
|
+
meta
|
251
|
+
Hash or array with custom metadata.
|
252
|
+
|
253
|
+
show
|
254
|
+
Resource is hidden from documentation when set to false (true by default)
|
255
|
+
|
256
|
+
Example:
|
257
|
+
~~~~~~~~
|
258
|
+
|
259
|
+
.. code:: ruby
|
260
|
+
|
261
|
+
# The simplest case: just load the paths from routes.rb
|
262
|
+
api!
|
263
|
+
def index
|
264
|
+
end
|
265
|
+
|
266
|
+
# More complex example
|
267
|
+
api :GET, "/users/:id", "Show user profile"
|
268
|
+
show false
|
269
|
+
error :code => 401, :desc => "Unauthorized"
|
270
|
+
error :code => 404, :desc => "Not Found", :meta => {:anything => "you can think of"}
|
271
|
+
param :session, String, :desc => "user is logged in", :required => true
|
272
|
+
param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
|
273
|
+
param :array_param, [100, "one", "two", 1, 2], :desc => "array validator"
|
274
|
+
param :boolean_param, [true, false], :desc => "array validator with boolean"
|
275
|
+
param :proc_param, lambda { |val|
|
276
|
+
val == "param value" ? true : "The only good value is 'param value'."
|
277
|
+
}, :desc => "proc validator"
|
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'
|
288
|
+
description "method description"
|
289
|
+
formats ['json', 'jsonp', 'xml']
|
290
|
+
meta :message => "Some very important info"
|
291
|
+
example " 'user': {...} "
|
292
|
+
see "users#showme", "link description"
|
293
|
+
see :link => "users#update", :desc => "another link description"
|
294
|
+
def show
|
295
|
+
#...
|
296
|
+
end
|
297
|
+
|
298
|
+
Parameter Description
|
299
|
+
---------------------
|
300
|
+
|
301
|
+
Use ``param`` to describe every possible parameter. You can use the Hash validator
|
302
|
+
in conjunction with a block given to the param method to describe nested parameters.
|
303
|
+
|
304
|
+
name
|
305
|
+
The first argument is the parameter name as a symbol.
|
306
|
+
|
307
|
+
validator
|
308
|
+
Second parameter is the parameter validator, choose one from section `Validators`_
|
309
|
+
|
310
|
+
desc
|
311
|
+
Parameter description.
|
312
|
+
|
313
|
+
required
|
314
|
+
Set this true/false to make it required/optional. Default is optional
|
315
|
+
|
316
|
+
allow_nil
|
317
|
+
Setting this to true means that ``nil`` can be passed.
|
318
|
+
|
319
|
+
allow_blank
|
320
|
+
Like ``allow_nil``, but for blank values. ``false``, ``""``, ``' '``, ``nil``, ``[]``, and ``{}`` are all blank.
|
321
|
+
|
322
|
+
as
|
323
|
+
Used by the processing functionality to change the name of a key params.
|
324
|
+
|
325
|
+
meta
|
326
|
+
Hash or array with custom metadata.
|
327
|
+
|
328
|
+
show
|
329
|
+
Parameter is hidden from documentation when set to false (true by default)
|
330
|
+
|
331
|
+
missing_message
|
332
|
+
Specify the message to be returned if the parameter is missing as a string or Proc.
|
333
|
+
Defaults to ``Missing parameter #{name}`` if not specified.
|
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
|
+
|
342
|
+
Example:
|
343
|
+
~~~~~~~~
|
344
|
+
|
345
|
+
.. code:: ruby
|
346
|
+
|
347
|
+
param :user, Hash, :desc => "User info" do
|
348
|
+
param :username, String, :desc => "Username for login", :required => true
|
349
|
+
param :password, String, :desc => "Password for login", :required => true
|
350
|
+
param :membership, ["standard","premium"], :desc => "User membership"
|
351
|
+
param :admin_override, String, :desc => "Not shown in documentation", :show => false
|
352
|
+
param :ip_address, String, :desc => "IP address", :required => true, :missing_message => lambda { I18n.t("ip_address.required") }
|
353
|
+
end
|
354
|
+
def create
|
355
|
+
#...
|
356
|
+
end
|
357
|
+
|
358
|
+
DRY with param_group
|
359
|
+
--------------------
|
360
|
+
|
361
|
+
Often, params occur together in more actions. Typically, most of the
|
362
|
+
params for ``create`` and ``update`` actions are shared between them.
|
363
|
+
|
364
|
+
These params can be extracted with ``def_param_group`` and
|
365
|
+
``param_group`` keywords.
|
366
|
+
|
367
|
+
The definition is looked up in the scope of the controller. If the
|
368
|
+
group is defined in a different controller, it might be referenced by
|
369
|
+
specifying the second argument.
|
370
|
+
|
371
|
+
Example:
|
372
|
+
~~~~~~~~
|
373
|
+
|
374
|
+
.. code:: ruby
|
375
|
+
|
376
|
+
# v1/users_controller.rb
|
377
|
+
def_param_group :address do
|
378
|
+
param :street, String
|
379
|
+
param :number, Integer
|
380
|
+
param :zip, String
|
381
|
+
end
|
382
|
+
|
383
|
+
def_param_group :user do
|
384
|
+
param :user, Hash do
|
385
|
+
param :name, String, "Name of the user"
|
386
|
+
param_group :address
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
api :POST, "/users", "Create an user"
|
391
|
+
param_group :user
|
392
|
+
def create
|
393
|
+
# ...
|
394
|
+
end
|
395
|
+
|
396
|
+
api :PUT, "/users/:id", "Update an user"
|
397
|
+
param_group :user
|
398
|
+
def update
|
399
|
+
# ...
|
400
|
+
end
|
401
|
+
|
402
|
+
# v2/users_controller.rb
|
403
|
+
api :POST, "/users", "Create an user"
|
404
|
+
param_group :user, V1::UsersController
|
405
|
+
def create
|
406
|
+
# ...
|
407
|
+
end
|
408
|
+
|
409
|
+
Action Aware params
|
410
|
+
-------------------
|
411
|
+
|
412
|
+
In CRUD operations, this pattern occurs quite often - params that need
|
413
|
+
to be set are:
|
414
|
+
|
415
|
+
* for create action: ``required => true`` and ``allow_nil => false``
|
416
|
+
* for update action: ``required => false`` and ``allow_nil => false``
|
417
|
+
|
418
|
+
This makes it hard to share the param definitions across theses
|
419
|
+
actions. Therefore, you can make the description a bit smarter by
|
420
|
+
setting ``:action_aware => true``.
|
421
|
+
|
422
|
+
You can specify explicitly how the param group should be evaluated
|
423
|
+
with ``:as`` option (either :create or :update)
|
424
|
+
|
425
|
+
Example
|
426
|
+
~~~~~~~
|
427
|
+
|
428
|
+
.. code:: ruby
|
429
|
+
|
430
|
+
def_param_group :user do
|
431
|
+
param :user, Hash, :action_aware => true do
|
432
|
+
param :name, String, :required => true
|
433
|
+
param :description, String
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
api :POST, "/users", "Create an user"
|
438
|
+
param_group :user
|
439
|
+
def create
|
440
|
+
# ...
|
441
|
+
end
|
442
|
+
|
443
|
+
api :PUT, "/users/admin", "Create an admin"
|
444
|
+
param_group :user, :as => :create
|
445
|
+
def create_admin
|
446
|
+
# ...
|
447
|
+
end
|
448
|
+
|
449
|
+
api :PUT, "/users/:id", "Update an user"
|
450
|
+
param_group :user
|
451
|
+
def update
|
452
|
+
# ...
|
453
|
+
end
|
454
|
+
|
455
|
+
In this case, ``user[name]`` will be not be allowed nil for all
|
456
|
+
actions and required only for ``create`` and ``create_admin``. Params
|
457
|
+
with ``allow_nil`` set explicitly don't have this value changed.
|
458
|
+
|
459
|
+
Action awareness is inherited from ancestors (in terms of
|
460
|
+
nested params).
|
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
|
+
|
747
|
+
Concerns
|
748
|
+
--------
|
749
|
+
|
750
|
+
Sometimes, the actions are not defined in the controller class
|
751
|
+
directly but included from a module instead. You can load the Apipie
|
752
|
+
DSL into the module by extending it with ``Apipie::DSL::Concern``.
|
753
|
+
|
754
|
+
The module can be used in more controllers. Therefore there is a way to
|
755
|
+
substitute parts of the documentation in the module with controller
|
756
|
+
specific values. These substitutions can be stated explicitly with
|
757
|
+
``apipie_concern_subst(:key => "value")`` (needs to be called before
|
758
|
+
the module is included to take effect). The substitutions are
|
759
|
+
performed in the paths and descriptions of APIs and names and descriptions
|
760
|
+
of params.
|
761
|
+
|
762
|
+
There are some default substitutions available:
|
763
|
+
|
764
|
+
:controller_path
|
765
|
+
value of ``controller.controller_path``, e.g. ``api/users`` for
|
766
|
+
``Api::UsersController``. Only if not using the ``api!`` keyword.
|
767
|
+
|
768
|
+
:resource_id
|
769
|
+
Apipie identifier of the resource, e.g. ``users`` for
|
770
|
+
``Api::UsersController`` or set by ``resource_id``
|
771
|
+
|
772
|
+
Example
|
773
|
+
~~~~~~~
|
774
|
+
|
775
|
+
.. code:: ruby
|
776
|
+
|
777
|
+
# users_module.rb
|
778
|
+
module UsersModule
|
779
|
+
extend Apipie::DSL::Concern
|
780
|
+
|
781
|
+
api :GET, '/:controller_path', 'List :resource_id'
|
782
|
+
def index
|
783
|
+
# ...
|
784
|
+
end
|
785
|
+
|
786
|
+
api! 'Show a :resource'
|
787
|
+
def show
|
788
|
+
# ...
|
789
|
+
end
|
790
|
+
|
791
|
+
api :POST, '/:resource_id', "Create a :resource"
|
792
|
+
param :concern, Hash, :required => true
|
793
|
+
param :name, String, 'Name of a :resource'
|
794
|
+
param :resource_type, ['standard','vip']
|
795
|
+
end
|
796
|
+
def create
|
797
|
+
# ...
|
798
|
+
end
|
799
|
+
|
800
|
+
api :GET, '/:resource_id/:custom_subst'
|
801
|
+
def custom
|
802
|
+
# ...
|
803
|
+
end
|
804
|
+
end
|
805
|
+
|
806
|
+
# users_controller.rb
|
807
|
+
class UsersController < ApplicationController
|
808
|
+
|
809
|
+
resource_description { resource_id 'customers' }
|
810
|
+
|
811
|
+
apipie_concern_subst(:custom_subst => 'custom', :resource => 'customer')
|
812
|
+
include UsersModule
|
813
|
+
|
814
|
+
# the following paths are documented
|
815
|
+
# api :GET, '/users'
|
816
|
+
# api :GET, '/customers/:id', 'Show a customer'
|
817
|
+
# api :POST, '/customers', 'Create a customer'
|
818
|
+
# param :customer, :required => true do
|
819
|
+
# param :name, String, 'Name of a customer'
|
820
|
+
# param :customer_type, ['standard', 'vip']
|
821
|
+
# end
|
822
|
+
# api :GET, '/customers/:custom'
|
823
|
+
end
|
824
|
+
|
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
|
+
|
923
|
+
|
924
|
+
=========================
|
925
|
+
Configuration Reference
|
926
|
+
=========================
|
927
|
+
|
928
|
+
Create a configuration file in e.g. ``/config/initializers/apipie.rb``.
|
929
|
+
You can set the application name, footer text, API and documentation base URL
|
930
|
+
and turn off validations. You can also choose your favorite markup language
|
931
|
+
for full descriptions.
|
932
|
+
|
933
|
+
app_name
|
934
|
+
Name of your application; used in breadcrumbs navigation.
|
935
|
+
|
936
|
+
copyright
|
937
|
+
Copyright information (shown in page footer).
|
938
|
+
|
939
|
+
compress_examples
|
940
|
+
If ``true`` recorded examples are compressed using ``Zlib``. Useful for big test-suits.
|
941
|
+
|
942
|
+
doc_base_url
|
943
|
+
Documentation frontend base url.
|
944
|
+
|
945
|
+
api_base_url
|
946
|
+
Base url for default version of your API. To set it for specific version use ``config.api_base_url[version] = url``.
|
947
|
+
|
948
|
+
default_version
|
949
|
+
Default API version to be used (1.0 by default)
|
950
|
+
|
951
|
+
validate
|
952
|
+
Parameters validation is turned off when set to false. When set to
|
953
|
+
``:explicitly``, you must invoke parameter validation yourself by calling
|
954
|
+
controller method ``apipie_validations`` (typically in a before_filter).
|
955
|
+
When set to ``:implicitly`` (or just true), your controller's action
|
956
|
+
methods are wrapped with generated methods which call ``apipie_validations``,
|
957
|
+
and then call the action method. (``:implicitly`` by default)
|
958
|
+
|
959
|
+
validate_value
|
960
|
+
Check the value of params against specified validators (true by
|
961
|
+
default)
|
962
|
+
|
963
|
+
validate_presence
|
964
|
+
Check the params presence against the documentation.
|
965
|
+
|
966
|
+
validate_key
|
967
|
+
Check the received params to ensure they are defined in the API. (false by default)
|
968
|
+
|
969
|
+
process_params
|
970
|
+
Process and extract the parameter defined from the params of the request
|
971
|
+
to the api_params variable
|
972
|
+
|
973
|
+
app_info
|
974
|
+
Application long description.
|
975
|
+
|
976
|
+
reload_controllers
|
977
|
+
Set to enable/disable reloading controllers (and the documentation with it). Enabled by default in development.
|
978
|
+
|
979
|
+
api_controllers_matcher
|
980
|
+
For reloading to work properly you need to specify where your API controllers are. Can be an array if multiple paths are needed
|
981
|
+
|
982
|
+
api_routes
|
983
|
+
Set if your application uses a custom API router, different from the Rails
|
984
|
+
default
|
985
|
+
|
986
|
+
routes_formatter
|
987
|
+
An object providing the translation from the Rails routes to the
|
988
|
+
format usable in the documentation when using the `api!` keyword. By
|
989
|
+
default, the ``Apipie::RoutesFormatter`` is used.
|
990
|
+
|
991
|
+
markup
|
992
|
+
You can choose markup language for descriptions of your application,
|
993
|
+
resources and methods. RDoc is the default but you can choose from
|
994
|
+
Apipie::Markup::Markdown.new or Apipie::Markup::Textile.new.
|
995
|
+
In order to use Markdown you need Maruku gem and for Textile you
|
996
|
+
need RedCloth. Add those to your gemfile and run bundle if you
|
997
|
+
want to use them. You can also add any other markup language
|
998
|
+
processor.
|
999
|
+
|
1000
|
+
layout
|
1001
|
+
Name of a layout template to use instead of Apipie's layout. You can use
|
1002
|
+
Apipie.include_stylesheets and Apipie.include_javascripts helpers to include
|
1003
|
+
Apipie's stylesheets and javascripts.
|
1004
|
+
|
1005
|
+
ignored
|
1006
|
+
An array of controller names (strings) (might include actions as well)
|
1007
|
+
to be ignored when generationg the documentation
|
1008
|
+
e.g. ``%w[Api::CommentsController Api::PostsController#post]``
|
1009
|
+
|
1010
|
+
namespaced_resources
|
1011
|
+
Use controller paths instead of controller names as resource id.
|
1012
|
+
This prevents same named controllers overwriting each other.
|
1013
|
+
|
1014
|
+
authenticate
|
1015
|
+
Pass a proc in order to authenticate user. Pass nil for
|
1016
|
+
no authentication (by default).
|
1017
|
+
|
1018
|
+
authorize
|
1019
|
+
Pass a proc in order to authorize controllers and methods. The Proc is evaluated in the controller context.
|
1020
|
+
|
1021
|
+
show_all_examples
|
1022
|
+
Set this to true to set show_in_doc=1 in all recorded examples
|
1023
|
+
|
1024
|
+
link_extension
|
1025
|
+
The extension to use for API pages ('.html' by default). Link extensions
|
1026
|
+
in static API docs cannot be changed from '.html'.
|
1027
|
+
|
1028
|
+
languages
|
1029
|
+
List of languages the API documentation should be translated into. Empty by default.
|
1030
|
+
|
1031
|
+
default_locale
|
1032
|
+
Locale used for generating documentation when no specific locale is set.
|
1033
|
+
Set to 'en' by default.
|
1034
|
+
|
1035
|
+
locale
|
1036
|
+
Pass locale setter/getter
|
1037
|
+
|
1038
|
+
.. code:: ruby
|
1039
|
+
|
1040
|
+
config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
|
1041
|
+
|
1042
|
+
translate
|
1043
|
+
Pass proc to translate strings using the localization library your project uses.
|
1044
|
+
For example see `Localization`_
|
1045
|
+
|
1046
|
+
Example:
|
1047
|
+
|
1048
|
+
.. code:: ruby
|
1049
|
+
|
1050
|
+
Apipie.configure do |config|
|
1051
|
+
config.app_name = "Test app"
|
1052
|
+
config.copyright = "© 2012 Pavel Pokorny"
|
1053
|
+
config.doc_base_url = "/apidoc"
|
1054
|
+
config.api_base_url = "/api"
|
1055
|
+
config.validate = false
|
1056
|
+
config.markup = Apipie::Markup::Markdown.new
|
1057
|
+
config.reload_controllers = Rails.env.development?
|
1058
|
+
config.api_controllers_matcher = File.join(Rails.root, "app", "controllers", "**","*.rb")
|
1059
|
+
config.api_routes = Rails.application.routes
|
1060
|
+
config.app_info["1.0"] = "
|
1061
|
+
This is where you can inform user about your application and API
|
1062
|
+
in general.
|
1063
|
+
"
|
1064
|
+
config.authenticate = Proc.new do
|
1065
|
+
authenticate_or_request_with_http_basic do |username, password|
|
1066
|
+
username == "test" && password == "supersecretpassword"
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
config.authorize = Proc.new do |controller, method, doc|
|
1070
|
+
!method # show all controller doc, but no method docs.
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
checksum_path
|
1075
|
+
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]``
|
1076
|
+
|
1077
|
+
update_checksum
|
1078
|
+
If set to true, the checksum is recalculated with every documentation_reload call
|
1079
|
+
|
1080
|
+
========================
|
1081
|
+
Rails Routes Integration
|
1082
|
+
========================
|
1083
|
+
|
1084
|
+
Apipie is able to load the information about the paths based on the
|
1085
|
+
routes defined in the Rails application, by using the `api!` keyword
|
1086
|
+
in the DSL.
|
1087
|
+
|
1088
|
+
It should be usable out of box, however, one might want
|
1089
|
+
to do some customization (such as omitting some implicit parameters in
|
1090
|
+
the path etc.). For this kind of customizations one can create a new
|
1091
|
+
formatter and pass as the ``Apipie.configuration.routes_formatter``
|
1092
|
+
option, like this:
|
1093
|
+
|
1094
|
+
.. code:: ruby
|
1095
|
+
|
1096
|
+
class MyFormatter < Apipie::RoutesFormatter
|
1097
|
+
def format_path(route)
|
1098
|
+
super.gsub(/\(.*?\)/, '').gsub('//','') # hide all implicit parameters
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
Apipie.configure do |config|
|
1103
|
+
...
|
1104
|
+
config.routes_formatter = MyFormatter.new
|
1105
|
+
...
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
A similar way can be used to influence things like order, or a description
|
1109
|
+
of the loaded APIs, even omitting some paths if needed.
|
1110
|
+
|
1111
|
+
============
|
1112
|
+
Processing
|
1113
|
+
============
|
1114
|
+
|
1115
|
+
The goal is to extract and pre-process parameters of the request.
|
1116
|
+
|
1117
|
+
For example Rails, by default, transforms an empty array to nil value. Perhaps
|
1118
|
+
you want to transform it again into an empty array. Or you
|
1119
|
+
want to support an enumeration type (comma separated values) and
|
1120
|
+
you want to automatically transform this string into an array.
|
1121
|
+
|
1122
|
+
To use it, set the ``process_params`` configuration variable to true.
|
1123
|
+
|
1124
|
+
Also by using ``as`` you can separate your API parameter
|
1125
|
+
names from the names you are using inside your code.
|
1126
|
+
|
1127
|
+
To implement it, you just have to write a process_value
|
1128
|
+
function in your validator:
|
1129
|
+
|
1130
|
+
For an enumeration type:
|
1131
|
+
|
1132
|
+
.. code:: ruby
|
1133
|
+
|
1134
|
+
def process_value(value)
|
1135
|
+
value ? value.split(',') : []
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
============
|
1139
|
+
Validators
|
1140
|
+
============
|
1141
|
+
|
1142
|
+
Every parameter needs to have an associated validator. For now there are some
|
1143
|
+
basic validators. You can always provide your own to achieve complex
|
1144
|
+
results.
|
1145
|
+
|
1146
|
+
If validations are enabled (default state) the parameters of every
|
1147
|
+
request are validated. If the value is wrong an +ArgumentError+ exception
|
1148
|
+
is raised and can be rescued and processed. It contains a description
|
1149
|
+
of the parameter value expectations. Validations can be turned off
|
1150
|
+
in the configuration file.
|
1151
|
+
|
1152
|
+
Parameter validation normally happens after before_filters, just before
|
1153
|
+
your controller method is invoked. If you prefer to control when parameter
|
1154
|
+
validation occurs, set the configuration parameter ``validate`` to ``:explicitly``.
|
1155
|
+
You must then call the ``apipie_validations`` method yourself, e.g.:
|
1156
|
+
|
1157
|
+
.. code:: ruby
|
1158
|
+
|
1159
|
+
before_filter :apipie_validations
|
1160
|
+
|
1161
|
+
This is useful if you have before_filters which use parameter values: just add them
|
1162
|
+
after the ``apipie_validations`` before_filter.
|
1163
|
+
|
1164
|
+
TypeValidator
|
1165
|
+
-------------
|
1166
|
+
Check the parameter type. Only String, Hash and Array are supported
|
1167
|
+
for the sake of simplicity. Read more to find out how to add
|
1168
|
+
your own validator.
|
1169
|
+
|
1170
|
+
.. code:: ruby
|
1171
|
+
|
1172
|
+
param :session, String, :desc => "user is logged in", :required => true
|
1173
|
+
param :facts, Hash, :desc => "Additional optional facts about the user"
|
1174
|
+
|
1175
|
+
|
1176
|
+
RegexpValidator
|
1177
|
+
---------------
|
1178
|
+
Check parameter value against given regular expression.
|
1179
|
+
|
1180
|
+
.. code:: ruby
|
1181
|
+
|
1182
|
+
param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
|
1183
|
+
|
1184
|
+
|
1185
|
+
EnumValidator
|
1186
|
+
--------------
|
1187
|
+
|
1188
|
+
Check if parameter value is included in the given array.
|
1189
|
+
|
1190
|
+
.. code:: ruby
|
1191
|
+
|
1192
|
+
param :enum_param, [100, "one", "two", 1, 2], :desc => "enum validator"
|
1193
|
+
|
1194
|
+
|
1195
|
+
ProcValidator
|
1196
|
+
-------------
|
1197
|
+
|
1198
|
+
If you need more complex validation and you know you won't reuse it, you
|
1199
|
+
can use the Proc/lambda validator. Provide your own Proc, taking the value
|
1200
|
+
of the parameter as the only argument. Return true if value passes validation
|
1201
|
+
or return some text about what is wrong otherwise. _Don't use the keyword *return*
|
1202
|
+
if you provide an instance of Proc (with lambda it is ok), just use the last
|
1203
|
+
statement return property of ruby.
|
1204
|
+
|
1205
|
+
.. code:: ruby
|
1206
|
+
|
1207
|
+
param :proc_param, lambda { |val|
|
1208
|
+
val == "param value" ? true : "The only good value is 'param value'."
|
1209
|
+
}, :desc => "proc validator"
|
1210
|
+
|
1211
|
+
|
1212
|
+
HashValidator
|
1213
|
+
-------------
|
1214
|
+
|
1215
|
+
You can describe hash parameters in depth if you provide a block with a
|
1216
|
+
description of nested values.
|
1217
|
+
|
1218
|
+
.. code:: ruby
|
1219
|
+
|
1220
|
+
param :user, Hash, :desc => "User info" do
|
1221
|
+
param :username, String, :desc => "Username for login", :required => true
|
1222
|
+
param :password, String, :desc => "Password for login", :required => true
|
1223
|
+
param :membership, ["standard","premium"], :desc => "User membership"
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
|
1227
|
+
NilValidator
|
1228
|
+
------------
|
1229
|
+
|
1230
|
+
In fact there isn't any NilValidator, but setting it to nil can be used to
|
1231
|
+
override parameters described on the resource level.
|
1232
|
+
|
1233
|
+
.. code:: ruby
|
1234
|
+
|
1235
|
+
param :user, nil
|
1236
|
+
def destroy
|
1237
|
+
#...
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
NumberValidator
|
1241
|
+
---------------
|
1242
|
+
|
1243
|
+
Check if the parameter is a positive integer number or zero
|
1244
|
+
|
1245
|
+
.. code:: ruby
|
1246
|
+
|
1247
|
+
param :product_id, :number, :desc => "Identifier of the product", :required => true
|
1248
|
+
param :quantity, :number, :desc => "Number of products to order", :required => true
|
1249
|
+
|
1250
|
+
DecimalValidator
|
1251
|
+
--------------
|
1252
|
+
|
1253
|
+
Check if the parameter is a decimal number
|
1254
|
+
|
1255
|
+
.. code:: ruby
|
1256
|
+
|
1257
|
+
param :latitude, :decimal, :desc => "Geographic latitude", :required => true
|
1258
|
+
param :longitude, :decimal, :desc => "Geographic longitude", :required => true
|
1259
|
+
|
1260
|
+
ArrayValidator
|
1261
|
+
--------------
|
1262
|
+
|
1263
|
+
Check if the parameter is an array
|
1264
|
+
|
1265
|
+
Additional options
|
1266
|
+
~~~~~~~~~~~~~~~~~
|
1267
|
+
|
1268
|
+
of
|
1269
|
+
Specify the type of items. If not given it accepts an array of any item type
|
1270
|
+
|
1271
|
+
in
|
1272
|
+
Specify an array of valid item values.
|
1273
|
+
|
1274
|
+
Examples
|
1275
|
+
~~~~~~~~
|
1276
|
+
|
1277
|
+
Assert `things` is an array of any items
|
1278
|
+
|
1279
|
+
.. code:: ruby
|
1280
|
+
|
1281
|
+
param :things, Array
|
1282
|
+
|
1283
|
+
Assert `hits` must be an array of integer values
|
1284
|
+
|
1285
|
+
.. code:: ruby
|
1286
|
+
|
1287
|
+
param :hits, Array, of: Integer
|
1288
|
+
|
1289
|
+
Assert `colors` must be an array of valid string values
|
1290
|
+
|
1291
|
+
.. code:: ruby
|
1292
|
+
|
1293
|
+
param :colors, Array, in: ["red", "green", "blue"]
|
1294
|
+
|
1295
|
+
|
1296
|
+
The retrieving of valid items can be deferred until needed using a lambda. It is evaluated only once
|
1297
|
+
|
1298
|
+
.. code:: ruby
|
1299
|
+
|
1300
|
+
param :colors, Array, in: -> { Color.all.pluck(:name) }
|
1301
|
+
|
1302
|
+
|
1303
|
+
NestedValidator
|
1304
|
+
-------------
|
1305
|
+
|
1306
|
+
You can describe nested parameters in depth if you provide a block with a
|
1307
|
+
description of nested values.
|
1308
|
+
|
1309
|
+
.. code:: ruby
|
1310
|
+
|
1311
|
+
param :comments, Array, :desc => "User comments" do
|
1312
|
+
param :name, String, :desc => "Name of the comment", :required => true
|
1313
|
+
param :comment, String, :desc => "Full comment", :required => true
|
1314
|
+
end
|
1315
|
+
|
1316
|
+
|
1317
|
+
|
1318
|
+
Adding custom validator
|
1319
|
+
-----------------------
|
1320
|
+
|
1321
|
+
Only basic validators are included but it is really easy to add your own.
|
1322
|
+
Create a new initializer with a subclass of Apipie::Validator::BaseValidator.
|
1323
|
+
Two methods are required to implement this - instance method
|
1324
|
+
:code:`validate(value)` and class method
|
1325
|
+
:code:`build(param_description, argument, options, block)`.
|
1326
|
+
|
1327
|
+
When searching for the validator +build+ method, every subclass of
|
1328
|
+
Apipie::Validator::BaseValidator is called. The first one that returns the
|
1329
|
+
constructed validator object is used.
|
1330
|
+
|
1331
|
+
Example: Adding IntegerValidator
|
1332
|
+
|
1333
|
+
We want to check if the parameter value is an integer like this:
|
1334
|
+
|
1335
|
+
.. code:: ruby
|
1336
|
+
|
1337
|
+
param :id, Integer, :desc => "Company ID"
|
1338
|
+
|
1339
|
+
So we create apipie_validators.rb initializer with this content:
|
1340
|
+
|
1341
|
+
.. code:: ruby
|
1342
|
+
|
1343
|
+
class IntegerValidator < Apipie::Validator::BaseValidator
|
1344
|
+
|
1345
|
+
def initialize(param_description, argument)
|
1346
|
+
super(param_description)
|
1347
|
+
@type = argument
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
def validate(value)
|
1351
|
+
return false if value.nil?
|
1352
|
+
!!(value.to_s =~ /^[-+]?[0-9]+$/)
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
def self.build(param_description, argument, options, block)
|
1356
|
+
if argument == Integer || argument == Fixnum
|
1357
|
+
self.new(param_description, argument)
|
1358
|
+
end
|
1359
|
+
end
|
1360
|
+
|
1361
|
+
def description
|
1362
|
+
"Must be #{@type}."
|
1363
|
+
end
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
Parameters of the build method:
|
1367
|
+
|
1368
|
+
param_description
|
1369
|
+
Instance of Apipie::ParamDescription contains all
|
1370
|
+
given information about the validated parameter.
|
1371
|
+
|
1372
|
+
argument
|
1373
|
+
Specified validator; in our example it is +Integer+
|
1374
|
+
|
1375
|
+
options
|
1376
|
+
Hash with specified options, for us just ``{:desc => "Company ID"}``
|
1377
|
+
|
1378
|
+
block
|
1379
|
+
Block converted into Proc, use it as you desire. In this example nil.
|
1380
|
+
|
1381
|
+
|
1382
|
+
============
|
1383
|
+
Versioning
|
1384
|
+
============
|
1385
|
+
|
1386
|
+
Every resource/method can belong to one or more versions. The version is
|
1387
|
+
specified with the `api_version` DSL keyword. When not specified,
|
1388
|
+
the resource belongs to `config.default_version` ("1.0" by default)
|
1389
|
+
|
1390
|
+
.. code:: ruby
|
1391
|
+
|
1392
|
+
resource_description do
|
1393
|
+
api_versions "1", "2"
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
api :GET, "/api/users/", "List: users"
|
1397
|
+
api_version "1"
|
1398
|
+
def index
|
1399
|
+
# ...
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
api :GET, "/api/users/", "List: users", :deprecated => true
|
1403
|
+
|
1404
|
+
In the example above we say the whole controller/resource is defined
|
1405
|
+
for versions "1" and "2", but we override this by explicitly saying
|
1406
|
+
`index` belongs only to version "1". Also, inheritance works (therefore
|
1407
|
+
we can specify the api_version for the parent controller, and all
|
1408
|
+
children will know about that). Routes can be flagged as deprecated,
|
1409
|
+
and an annotation will be added to them when viewing in the API
|
1410
|
+
documentation.
|
1411
|
+
|
1412
|
+
From the Apipie API perspective, the resources belong to the version.
|
1413
|
+
With versioning, there are paths like this provided by apipie:
|
1414
|
+
|
1415
|
+
.. code::
|
1416
|
+
|
1417
|
+
/apipie/1/users/index
|
1418
|
+
/apipie/2/users/index
|
1419
|
+
|
1420
|
+
When not specifying the version explicitly in the path (or in DSL),
|
1421
|
+
default version (`Apipie.configuration.default_version`) is used
|
1422
|
+
instead ("1.0" by default). Therefore, an application that doesn't
|
1423
|
+
need versioning should work as before.
|
1424
|
+
|
1425
|
+
The static page generator takes a version parameter (or uses default).
|
1426
|
+
|
1427
|
+
You can specify the versions for the examples, with the `versions`
|
1428
|
+
keyword. It specifies the versions the example is used for. When not
|
1429
|
+
specified, it's shown in all versions with the given method.
|
1430
|
+
|
1431
|
+
When referencing or quering the resource/method descripion, this
|
1432
|
+
format should be used: "version#resource#method". When not specified,
|
1433
|
+
the default version is used instead.
|
1434
|
+
|
1435
|
+
|
1436
|
+
========
|
1437
|
+
Markup
|
1438
|
+
========
|
1439
|
+
|
1440
|
+
The default markup language is `RDoc
|
1441
|
+
<https://rdoc.github.io/rdoc/RDoc/Markup.html>`_. It can be changed in
|
1442
|
+
the config file (``config.markup=``) to one of these:
|
1443
|
+
|
1444
|
+
Markdown
|
1445
|
+
Use Apipie::Markup::Markdown.new. You need Maruku gem.
|
1446
|
+
|
1447
|
+
Textile
|
1448
|
+
Use Apipie::Markup::Textile.new. You need RedCloth gem.
|
1449
|
+
|
1450
|
+
Or provide you own object with a ``to_html(text)`` method.
|
1451
|
+
For inspiration, this is how Textile markup usage is implemented:
|
1452
|
+
|
1453
|
+
.. code:: ruby
|
1454
|
+
|
1455
|
+
class Textile
|
1456
|
+
def initialize
|
1457
|
+
require 'RedCloth'
|
1458
|
+
end
|
1459
|
+
def to_html(text)
|
1460
|
+
RedCloth.new(text).to_html
|
1461
|
+
end
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
============
|
1465
|
+
Localization
|
1466
|
+
============
|
1467
|
+
|
1468
|
+
Apipie has support for localized API documentation in both formats (JSON and HTML).
|
1469
|
+
Apipie uses the library I18n for localization of itself.
|
1470
|
+
Check ``config/locales`` directory for available translations.
|
1471
|
+
|
1472
|
+
A major part of strings in the documentation comes from the API.
|
1473
|
+
As preferences regarding localization libraries differ amongst project, Apipie needs to know how to set the locale for your project,
|
1474
|
+
and how to translate a string using the library your project uses. That can be done using lambdas in configuration.
|
1475
|
+
|
1476
|
+
Sample configuration when your project uses FastGettext
|
1477
|
+
|
1478
|
+
|
1479
|
+
.. code:: ruby
|
1480
|
+
|
1481
|
+
Apipie.configure do |config|
|
1482
|
+
...
|
1483
|
+
config.languages = ['en', 'cs']
|
1484
|
+
config.default_locale = 'en'
|
1485
|
+
config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
|
1486
|
+
config.translate = lambda do |str, loc|
|
1487
|
+
old_loc = FastGettext.locale
|
1488
|
+
FastGettext.set_locale(loc)
|
1489
|
+
trans = _(str)
|
1490
|
+
FastGettext.set_locale(old_loc)
|
1491
|
+
trans
|
1492
|
+
end
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
And the strings in the API documentation need to be marked with the ``N_()`` function
|
1496
|
+
|
1497
|
+
.. code:: ruby
|
1498
|
+
|
1499
|
+
api :GET, "/users/:id", N_("Show user profile")
|
1500
|
+
param :session, String, :desc => N_("user is logged in"), :required => true
|
1501
|
+
|
1502
|
+
|
1503
|
+
|
1504
|
+
When your project use I18n, localization related configuration could appear as follows
|
1505
|
+
|
1506
|
+
.. code:: ruby
|
1507
|
+
|
1508
|
+
Apipie.configure do |config|
|
1509
|
+
...
|
1510
|
+
config.languages = ['en', 'cs']
|
1511
|
+
config.default_locale = 'en'
|
1512
|
+
config.locale = lambda { |loc| loc ? I18n.locale = loc : I18n.locale }
|
1513
|
+
config.translate = lambda do |str, loc|
|
1514
|
+
return '' if str.blank?
|
1515
|
+
I18n.t str, locale: loc, scope: 'doc'
|
1516
|
+
end
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
And the strings in the API documentation needs to be in the form of translation keys
|
1520
|
+
|
1521
|
+
.. code:: ruby
|
1522
|
+
|
1523
|
+
api :GET, "/users/:id", "show_user_profile"
|
1524
|
+
param :session, String, :desc => "user_is_logged_in", :required => true
|
1525
|
+
|
1526
|
+
|
1527
|
+
The localized versions of the documentation are distinguished by language in the filename.
|
1528
|
+
E.g. ``doc/apidoc/apidoc.cs.html`` is static documentation in the Czech language.
|
1529
|
+
If the language is missing, e.g. ``doc/apidoc/apidoc.html``,
|
1530
|
+
the documentation is localized with the ``default_locale``.
|
1531
|
+
|
1532
|
+
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``
|
1533
|
+
|
1534
|
+
|
1535
|
+
================
|
1536
|
+
Modifying Views
|
1537
|
+
================
|
1538
|
+
|
1539
|
+
To modify the views of your documentation, run ``rails g apipie:views``.
|
1540
|
+
This will copy the Apipie views to ``app/views/apipie/apipies`` and
|
1541
|
+
``app/views/layouts/apipie``.
|
1542
|
+
|
1543
|
+
|
1544
|
+
==============
|
1545
|
+
Static files
|
1546
|
+
==============
|
1547
|
+
|
1548
|
+
To generate a static version of documentation (perhaps to put it on
|
1549
|
+
your project site or something), run the ``rake apipie:static`` task. It will
|
1550
|
+
create a set of HTML files (multi-pages, single-page, plain) in your doc
|
1551
|
+
directory. If you prefer a JSON version run ``rake apipie:static_json``.
|
1552
|
+
By default the documentation for the default API version is
|
1553
|
+
used. You can specify the version with ``rake apipie:static[2.0]``
|
1554
|
+
|
1555
|
+
When you want to avoid any unnecessary computation in production mode,
|
1556
|
+
you can generate a cache with ``rake apipie:cache`` and configure the
|
1557
|
+
app to use it in production with ``config.use_cache = Rails.env.production?``
|
1558
|
+
|
1559
|
+
Default cache dir is ``File.join(Rails.root, "public", "apipie-cache")``,
|
1560
|
+
you can change it to where you want, example: ``config.cache_dir = File.join(Rails.root, "doc", "apidoc")``.
|
1561
|
+
|
1562
|
+
If, for some complex cases, you need to generate/re-generate just part of the cache
|
1563
|
+
use ``rake apipie:cache cache_part=index`` resp. ``rake apipie:cache cache_part=resources``
|
1564
|
+
To generate it for different locations for further processing use ``rake apipie:cache OUT=/tmp/apipie_cache``.
|
1565
|
+
|
1566
|
+
.. _Swagger:
|
1567
|
+
|
1568
|
+
====================================
|
1569
|
+
Static Swagger (OpenAPI 2.0) files
|
1570
|
+
====================================
|
1571
|
+
|
1572
|
+
To generate a static Swagger definition file from the api, run ``rake apipie:static_swagger_json``.
|
1573
|
+
By default the documentation for the default API version is
|
1574
|
+
used. You can specify the version with ``rake apipie:static_swagger_json[2.0]``. A swagger file will be
|
1575
|
+
generated for each locale. The files will be generated in the same location as the static_json files, but
|
1576
|
+
instead of being named ``schema_apipie[.locale].json``, they will be called ``schema_swagger[.locale].json``.
|
1577
|
+
|
1578
|
+
Specifying default values for parameters
|
1579
|
+
-----------------------------------------
|
1580
|
+
Swagger allows method definitions to include an indication of the the default value for each parameter. To include such
|
1581
|
+
indications, use ``:default_value => <some value>`` in the parameter definition DSL. For example:
|
1582
|
+
|
1583
|
+
.. code:: ruby
|
1584
|
+
|
1585
|
+
param :do_something, Boolean, :desc => "take an action", :required => false, :default_value => false
|
1586
|
+
|
1587
|
+
|
1588
|
+
Generated Warnings
|
1589
|
+
-------------------
|
1590
|
+
The help identify potential improvements to your documentation, the swagger generation process issues warnings if
|
1591
|
+
it identifies various shortcomings of the DSL documentation. Each warning has a code to allow selective suppression
|
1592
|
+
(see swagger-specific configuration below)
|
1593
|
+
|
1594
|
+
:100: missing short description for method
|
1595
|
+
:101: added missing / at beginning of path
|
1596
|
+
:102: no return codes specified for method
|
1597
|
+
:103: a parameter is a generic Hash without an internal type specification
|
1598
|
+
:104: a parameter is an 'in-path' parameter, but specified as 'not required' in the DSL
|
1599
|
+
:105: a parameter is optional but does not have a default value specified
|
1600
|
+
:106: a parameter was ommitted from the swagger output because it is a Hash without fields in a formData specification
|
1601
|
+
:107: a path parameter is not described
|
1602
|
+
:108: inferring that a parameter type is boolean because described as an enum with [false,true] values
|
1603
|
+
|
1604
|
+
|
1605
|
+
|
1606
|
+
Swagger-Specific Configuration Parameters
|
1607
|
+
-------------------------------------------------
|
1608
|
+
|
1609
|
+
There are several configuration parameters that determine the structure of the generated swagger file:
|
1610
|
+
|
1611
|
+
``config.swagger_content_type_input``
|
1612
|
+
If the value is ``:form_data`` - the swagger file will indicate that the server consumes the content types
|
1613
|
+
``application/x-www-form-urlencoded`` and ``multipart/form-data``. Non-path parameters will have the
|
1614
|
+
value ``"in": "formData"``. Note that parameters of type Hash that do not have any fields in them will *be ommitted*
|
1615
|
+
from the resulting files, as there is no way to describe them in swagger.
|
1616
|
+
|
1617
|
+
If the value is ``:json`` - the swagger file will indicate that the server consumes the content type
|
1618
|
+
``application/json``. All non-path parameters will be included in the schema of a single ``"in": "body"`` parameter
|
1619
|
+
of type ``object``.
|
1620
|
+
|
1621
|
+
You can specify the value of this configuration parameter as an additional input to the rake command (e.g.,
|
1622
|
+
``rake apipie:static_swagger_json[2.0,form_data]``).
|
1623
|
+
|
1624
|
+
``config.swagger_json_input_uses_refs``
|
1625
|
+
This parameter is only relevant if ``swagger_content_type_input`` is ``:json``.
|
1626
|
+
|
1627
|
+
If ``true``: the schema of the ``"in": "body"`` parameter of each method is given its own entry in the ``definitions``
|
1628
|
+
section, and is referenced using ``$ref`` from the method definition.
|
1629
|
+
|
1630
|
+
If ``false``: the body parameter definitions are inlined within the method definitions.
|
1631
|
+
|
1632
|
+
``config.swagger_include_warning_tags``
|
1633
|
+
If ``true``: in addition to tagging methods with the name of the resource they belong to, methods for which warnings
|
1634
|
+
have been issued will be tagged with.
|
1635
|
+
|
1636
|
+
``config.swagger_suppress_warnings``
|
1637
|
+
If ``false``: no warnings will be suppressed
|
1638
|
+
|
1639
|
+
If ``true``: all warnings will be suppressed
|
1640
|
+
|
1641
|
+
If an array of values (e.g., ``[100,102,107]``), only the warnings identified by the numbers in the array will be suppressed.
|
1642
|
+
|
1643
|
+
``config.swagger_api_host``
|
1644
|
+
The value to place in the swagger host field.
|
1645
|
+
|
1646
|
+
Default is ``localhost:3000``
|
1647
|
+
|
1648
|
+
If ``nil`` then then host field will not be included.
|
1649
|
+
|
1650
|
+
``config.swagger_allow_additional_properties_in_response``
|
1651
|
+
If ``false`` (default): response descriptions in the generated swagger will include an ``additional-properties: false``
|
1652
|
+
field
|
1653
|
+
|
1654
|
+
If ``true``: the ``additional-properties: false`` field will not be included in response object descriptions
|
1655
|
+
|
1656
|
+
|
1657
|
+
Known limitations of the current implementation
|
1658
|
+
-------------------------------------------------
|
1659
|
+
* There is currently no way to document the structure and content-type of the data returned from a method
|
1660
|
+
* Recorded examples are currently not included in the generated swagger file
|
1661
|
+
* The apipie ``formats`` value is ignored.
|
1662
|
+
* It is not possible to specify the "consumed" content type on a per-method basis
|
1663
|
+
* It is not possible to leverage all of the parameter type/format capabilities of swagger
|
1664
|
+
* Only OpenAPI 2.0 is supported
|
1665
|
+
* Responses are defined inline and not as a $ref
|
1666
|
+
|
1667
|
+
====================================
|
1668
|
+
Dynamic Swagger generation
|
1669
|
+
====================================
|
1670
|
+
|
1671
|
+
To generate swagger dynamically, use ``http://localhost:3000/apipie.json?type=swagger``.
|
1672
|
+
|
1673
|
+
Note that authorization is not supported for dynamic swagger generation, so if ``config.authorize`` is defined,
|
1674
|
+
dynamic swagger generation will be disabled.
|
1675
|
+
|
1676
|
+
Dynamically generated swagger is not cached, and is always generated on the fly.
|
1677
|
+
|
1678
|
+
|
1679
|
+
===================
|
1680
|
+
JSON checksums
|
1681
|
+
===================
|
1682
|
+
|
1683
|
+
If the API client needs to be sure that the JSON didn't changed, add
|
1684
|
+
the ``ApipieChecksumInHeaders`` middleware in your rails app.
|
1685
|
+
It can add a checksum of the entire JSON document in the response headers.
|
1686
|
+
|
1687
|
+
.. code::
|
1688
|
+
|
1689
|
+
"Apipie-Checksum"=>"fb81460e7f4e78d059f826624bdf9504"
|
1690
|
+
|
1691
|
+
`Apipie bindings <https://github.com/Apipie/apipie-bindings>`_ uses this feature to refresh its JSON cache.
|
1692
|
+
|
1693
|
+
To set it up add the following to your ``application.rb``
|
1694
|
+
|
1695
|
+
.. code::
|
1696
|
+
|
1697
|
+
require 'apipie/middleware/checksum_in_headers'
|
1698
|
+
# Add JSON checksum in headers for smarter caching
|
1699
|
+
config.middleware.use "Apipie::Middleware::ChecksumInHeaders"
|
1700
|
+
|
1701
|
+
And in your apipie initializer allow checksum calculation
|
1702
|
+
|
1703
|
+
.. code::
|
1704
|
+
|
1705
|
+
Apipie.configuration.update_checksum = true
|
1706
|
+
|
1707
|
+
|
1708
|
+
By default the header is added to responses for ``config.doc_base_url`` and ``/api``.
|
1709
|
+
It can be changed in configuration (see `Configuration Reference`_ for details).
|
1710
|
+
|
1711
|
+
The checksum calculation is lazy, and done with the first request. If you run with ``use_cache = true``,
|
1712
|
+
do not forget to run the rake task ``apipie:cache``.
|
1713
|
+
|
1714
|
+
|
1715
|
+
===================
|
1716
|
+
Tests Integration
|
1717
|
+
===================
|
1718
|
+
|
1719
|
+
Apipie integrates with automated testing in two ways. *Documentation
|
1720
|
+
bootstrapping* and *examples recording*.
|
1721
|
+
|
1722
|
+
Documentation Bootstrapping
|
1723
|
+
---------------------------
|
1724
|
+
|
1725
|
+
Let's say you have an application without REST API documentation.
|
1726
|
+
However you have a set of tests that are run against this API. A lot
|
1727
|
+
of information is already included in these tests, it just needs to be
|
1728
|
+
extracted somehow. Luckily, Apipie provides such a feature.
|
1729
|
+
|
1730
|
+
When running the tests, set the ``APIPIE_RECORD=params`` environment
|
1731
|
+
variable or call ``Apipie.record('params')`` from specs starter. You can either use it with functional tests:
|
1732
|
+
|
1733
|
+
.. code::
|
1734
|
+
|
1735
|
+
APIPIE_RECORD=params rake test:functionals
|
1736
|
+
|
1737
|
+
or you can run your server with this param, in case you run the tests
|
1738
|
+
against running server:
|
1739
|
+
|
1740
|
+
.. code::
|
1741
|
+
|
1742
|
+
APIPIE_RECORD=params rails server
|
1743
|
+
|
1744
|
+
When the process quits, the data from requests/responses are used to
|
1745
|
+
determine the documentation. It's quite raw, but it makes the initial
|
1746
|
+
phase much easier.
|
1747
|
+
|
1748
|
+
Examples Recording
|
1749
|
+
------------------
|
1750
|
+
|
1751
|
+
You can also use the tests to generate up-to-date examples for your
|
1752
|
+
code. Similar to the bootstrapping process, you can use it with functional
|
1753
|
+
tests or a running server, setting ``APIPIE_RECORD=examples`` or calling ``Apipie.record('examples')`` in your specs starter.
|
1754
|
+
|
1755
|
+
.. code::
|
1756
|
+
|
1757
|
+
APIPIE_RECORD=examples rake test:functionals
|
1758
|
+
APIPIE_RECORD=examples rails server
|
1759
|
+
|
1760
|
+
The data is written into ``doc/apipie_examples.yml``. By default,
|
1761
|
+
only the first example is shown for each action. You can customize
|
1762
|
+
this by setting the ``show_in_doc`` attribute at each example.
|
1763
|
+
|
1764
|
+
You can add a title to the examples (useful when showing more than
|
1765
|
+
one example per method) by adding a 'title' attribute.
|
1766
|
+
|
1767
|
+
.. code::
|
1768
|
+
|
1769
|
+
--- !omap
|
1770
|
+
- announcements#index:
|
1771
|
+
- !omap
|
1772
|
+
- title: This is a custom title for this example
|
1773
|
+
- verb: :GET
|
1774
|
+
- path: /api/blabla/1
|
1775
|
+
- versions:
|
1776
|
+
- '1.0'
|
1777
|
+
- query:
|
1778
|
+
- request_data:
|
1779
|
+
- response_data:
|
1780
|
+
...
|
1781
|
+
- code: 200
|
1782
|
+
- show_in_doc: 1 # If 1, show. If 0, do not show.
|
1783
|
+
- recorded: true
|
1784
|
+
|
1785
|
+
In RSpec you can add metadata to examples. We can use that feature
|
1786
|
+
to mark selected examples - the ones that perform the requests that we want to
|
1787
|
+
show as examples in the documentation.
|
1788
|
+
|
1789
|
+
For example, we can add ``show_in_doc`` to examples, like this:
|
1790
|
+
|
1791
|
+
.. code:: ruby
|
1792
|
+
|
1793
|
+
describe "This is the correct path" do
|
1794
|
+
it "some test", :show_in_doc do
|
1795
|
+
....
|
1796
|
+
end
|
1797
|
+
end
|
1798
|
+
|
1799
|
+
context "These are edge cases" do
|
1800
|
+
it "Can't authenticate" do
|
1801
|
+
....
|
1802
|
+
end
|
1803
|
+
|
1804
|
+
it "record not found" do
|
1805
|
+
....
|
1806
|
+
end
|
1807
|
+
end
|
1808
|
+
|
1809
|
+
And then configure RSpec in this way:
|
1810
|
+
|
1811
|
+
.. code:: ruby
|
1812
|
+
|
1813
|
+
RSpec.configure do |config|
|
1814
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
1815
|
+
config.filter_run :show_in_doc => true if ENV['APIPIE_RECORD']
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
This way, when running in recording mode, only the tests that have been marked with the
|
1819
|
+
``:show_in_doc`` metadata will be run, and hence only those will be used as examples.
|
1820
|
+
|
1821
|
+
Caveats
|
1822
|
+
-------
|
1823
|
+
|
1824
|
+
Make sure to enable ``config.render_views`` in your ``config/rails_helper.rb`` or
|
1825
|
+
``config/spec_helper.rb`` if you're using jbuilder, or you will get back empty results
|
1826
|
+
|
1827
|
+
====================
|
1828
|
+
Bindings Generator
|
1829
|
+
====================
|
1830
|
+
|
1831
|
+
In earlier versions (<= 0.0.13), there was a simple client generator
|
1832
|
+
as a part of Apipie gem. As more features and users came to Apipie,
|
1833
|
+
there was a greater need for changes on a per project basis. It's
|
1834
|
+
hard (or even impossible) to provide a generic solution for the client
|
1835
|
+
code. We also don't want to tell you what's the right way to do it
|
1836
|
+
(what gems to use, how the API should look like etc.).
|
1837
|
+
|
1838
|
+
Therefore you can't generate client code directly by a rake task in
|
1839
|
+
further versions.
|
1840
|
+
|
1841
|
+
There is, however, an even better and more flexible way to reuse your API
|
1842
|
+
documentation for this purpose: using the API the Apipie
|
1843
|
+
provides in the generator code. Check out our sister project
|
1844
|
+
`apipie-bindings <https://github.com/Apipie/apipie-bindings>`_, as they
|
1845
|
+
use exactly this approach. You also don't need to run the service,
|
1846
|
+
provided it uses Apipie as a backend.
|
1847
|
+
|
1848
|
+
And if you write one on your own, don't hesitate to share it with us!
|
1849
|
+
|
1850
|
+
|
1851
|
+
====================
|
1852
|
+
Disqus Integration
|
1853
|
+
====================
|
1854
|
+
|
1855
|
+
You can setup `Disqus <http://www.disqus.com>`_ discussion within
|
1856
|
+
your documentation. Just set the credentials in the Apipie
|
1857
|
+
configuration:
|
1858
|
+
|
1859
|
+
.. code:: ruby
|
1860
|
+
|
1861
|
+
config.disqus_shortname = "MyProjectDoc"
|
1862
|
+
|
1863
|
+
=====================
|
1864
|
+
External References
|
1865
|
+
=====================
|
1866
|
+
|
1867
|
+
* `Getting started tutorial <https://github.com/iNecas/apipie-demo>`_ -
|
1868
|
+
including examples of using the tests integration and versioning.
|
1869
|
+
|
1870
|
+
* `Real-world application usage <https://github.com/Katello/katello>`_
|
1871
|
+
|
1872
|
+
* `Read-world application usage with versioning <https://github.com/theforeman/foreman>`_
|
1873
|
+
|
1874
|
+
* `Using Apipie API to generate bindings <https://github.com/Apipie/apipie-bindings>`_
|