apipie-rails 0.5.7 → 0.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
- data/README.rst +320 -2
- data/lib/apipie-rails.rb +2 -0
- data/lib/apipie/application.rb +1 -1
- data/lib/apipie/configuration.rb +5 -2
- data/lib/apipie/dsl_definition.rb +69 -1
- data/lib/apipie/errors.rb +6 -1
- data/lib/apipie/extractor/writer.rb +65 -42
- data/lib/apipie/method_description.rb +32 -2
- data/lib/apipie/param_description.rb +19 -1
- data/lib/apipie/resource_description.rb +3 -1
- data/lib/apipie/response_description.rb +125 -0
- data/lib/apipie/response_description_adapter.rb +199 -0
- data/lib/apipie/swagger_generator.rb +106 -16
- data/lib/apipie/version.rb +1 -1
- data/spec/controllers/apipies_controller_spec.rb +1 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/pets_controller.rb +391 -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/lib/extractor/writer_spec.rb +32 -4
- data/spec/lib/method_description_spec.rb +27 -0
- data/spec/lib/swagger/rake_swagger_spec.rb +4 -0
- data/spec/lib/swagger/swagger_dsl_spec.rb +489 -0
- data/spec/spec_helper.rb +94 -0
- metadata +13 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97d15ca9f95ac7fc79b848f3a3207c22c8e69f4c
|
4
|
+
data.tar.gz: 5d0dcae7fea76412efec316d2774da51367cee44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8716a1ebb09f66511232cdc45756cef0794791b618ae0dec4c1455e25cc194a5e5ab6ae9ec49c4845d6390f969785f4fe1f69b7d0e783c903cbce0f21c4f4b71
|
7
|
+
data.tar.gz: 63a0482166b36b1d6c8e2d066b67cd76242495111a0a79296576a7505adf22070a8515ddef1d9136c91f2b502059e0a3a5b1a358ebc7e1cd4d75b0c8439b2537
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
Changelog
|
2
2
|
===========
|
3
3
|
|
4
|
+
v0.5.8
|
5
|
+
------
|
6
|
+
|
7
|
+
- Swagger json includes apipie's description as swagger's description [\#615](https://github.com/Apipie/apipie-rails/pull/615) ([gogotanaka](https://github.com/gogotanaka))
|
8
|
+
- Fix api! issue by using underscore when appending `controller` to the default controller string [\#613](https://github.com/Apipie/apipie-rails/pull/613) ([kevinmarx](https://github.com/kevinmarx))
|
9
|
+
- Possibility to compress examples [\#600](https://github.com/Apipie/apipie-rails/pull/600) ([Haniyya](https://github.com/Haniyya))
|
10
|
+
- Possibility to describe responses [\#588](https://github.com/Apipie/apipie-rails/pull/588) ([elasti-ron](https://github.com/elasti-ron))
|
11
|
+
|
4
12
|
v0.5.7
|
5
13
|
------
|
6
14
|
|
@@ -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
CHANGED
@@ -117,6 +117,9 @@ desc (also description and full_description)
|
|
117
117
|
param
|
118
118
|
Common params for all methods defined in controller/child controllers.
|
119
119
|
|
120
|
+
returns
|
121
|
+
Common responses for all methods defined in controller/child controllers.
|
122
|
+
|
120
123
|
api_base_url
|
121
124
|
What URL is the resource available under.
|
122
125
|
|
@@ -156,6 +159,9 @@ Example:
|
|
156
159
|
error 404, "Missing"
|
157
160
|
error 500, "Server crashed for some <%= reason %>", :meta => {:anything => "you can think of"}
|
158
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
|
159
165
|
meta :author => {:name => 'John', :surname => 'Doe'}
|
160
166
|
deprecated false
|
161
167
|
description <<-EOS
|
@@ -211,7 +217,10 @@ api_versions (also api_version)
|
|
211
217
|
What version(s) does the action belong to. (See `Versioning`_ for details.)
|
212
218
|
|
213
219
|
param
|
214
|
-
Look at Parameter description section for details.
|
220
|
+
Look at `Parameter description`_ section for details.
|
221
|
+
|
222
|
+
returns
|
223
|
+
Look at `Response description`_ section for details.
|
215
224
|
|
216
225
|
formats
|
217
226
|
Method level request / response formats.
|
@@ -261,6 +270,13 @@ Example:
|
|
261
270
|
val == "param value" ? true : "The only good value is 'param value'."
|
262
271
|
}, :desc => "proc validator"
|
263
272
|
param :param_with_metadata, String, :desc => "", :meta => [:your, :custom, :metadata]
|
273
|
+
returns :code => 200, :desc => "a successful response" do
|
274
|
+
property :value1, String, :desc => "A string value"
|
275
|
+
property :value2, Integer, :desc => "An integer value"
|
276
|
+
property :value3, Hash, :desc => "An object" do
|
277
|
+
property :enum1, ['v1', 'v2'], :desc => "One of 2 possible string values"
|
278
|
+
end
|
279
|
+
end
|
264
280
|
description "method description"
|
265
281
|
formats ['json', 'jsonp', 'xml']
|
266
282
|
meta :message => "Some very important info"
|
@@ -271,7 +287,6 @@ Example:
|
|
271
287
|
#...
|
272
288
|
end
|
273
289
|
|
274
|
-
|
275
290
|
Parameter Description
|
276
291
|
---------------------
|
277
292
|
|
@@ -309,6 +324,13 @@ missing_message
|
|
309
324
|
Specify the message to be returned if the parameter is missing as a string or Proc.
|
310
325
|
Defaults to ``Missing parameter #{name}`` if not specified.
|
311
326
|
|
327
|
+
only_in
|
328
|
+
This can be set to ``:request`` or ``:response``.
|
329
|
+
Setting to ``:response`` causes the param to be ignored when used as part of a request description.
|
330
|
+
Setting to ``:request`` causes this param to be ignored when used as part of a response description.
|
331
|
+
If ``only_in`` is not specified, the param definition is used for both requests and responses.
|
332
|
+
(Note that the keyword ``property`` is similar to ``param``, but it has a ``:only_in => :response`` default).
|
333
|
+
|
312
334
|
Example:
|
313
335
|
~~~~~~~~
|
314
336
|
|
@@ -429,6 +451,291 @@ with ``allow_nil`` set explicitly don't have this value changed.
|
|
429
451
|
Action awareness is inherited from ancestors (in terms of
|
430
452
|
nested params).
|
431
453
|
|
454
|
+
|
455
|
+
Response Description
|
456
|
+
--------------------
|
457
|
+
|
458
|
+
The response from an API call can be documented by adding a ``returns`` statement to the method
|
459
|
+
description. This is especially useful when using Apipie to auto-generate a machine-readable Swagger
|
460
|
+
definition of your API (see the `swagger`_ section for more details).
|
461
|
+
|
462
|
+
A ``returns`` statement has several possible formats:
|
463
|
+
|
464
|
+
.. code:: ruby
|
465
|
+
|
466
|
+
# format #1: reference to a param-group
|
467
|
+
returns <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
|
468
|
+
|
469
|
+
# format #2: inline response definition
|
470
|
+
returns :code => <number>|<http-response-code-symbol> [, :desc => <human-readable description>] do
|
471
|
+
# property ...
|
472
|
+
# property ...
|
473
|
+
# param_group ...
|
474
|
+
end
|
475
|
+
|
476
|
+
# format #3: describing an array-of-objects response
|
477
|
+
returns :array_of => <param-group-name> [, :code => <number>|<http-response-code-symbol>] [, :desc => <human-readable description>]
|
478
|
+
|
479
|
+
|
480
|
+
If the ``:code`` argument is ommitted, ``200`` is used.
|
481
|
+
|
482
|
+
|
483
|
+
Example
|
484
|
+
~~~~~~~
|
485
|
+
|
486
|
+
.. code:: ruby
|
487
|
+
|
488
|
+
# ------------------------------------------------
|
489
|
+
# Example of format #1 (reference to param-group):
|
490
|
+
# ------------------------------------------------
|
491
|
+
# the param_group :pet is defined here to describe the output returned by the method below.
|
492
|
+
def_param_group :pet do
|
493
|
+
property :pet_name, String, :desc => "Name of pet"
|
494
|
+
property :animal_type, ['dog','cat','iguana','kangaroo'], :desc => "Type of pet"
|
495
|
+
end
|
496
|
+
|
497
|
+
api :GET, "/pets/:id", "Get a pet record"
|
498
|
+
returns :pet, :desc => "The pet"
|
499
|
+
def show_detailed
|
500
|
+
render JSON({:pet_name => "Skippie", :animal_type => "kangaroo"})
|
501
|
+
end
|
502
|
+
|
503
|
+
# ------------------------------------------------
|
504
|
+
# Example of format #2 (inline):
|
505
|
+
# ------------------------------------------------
|
506
|
+
api :GET, "/pets/:id/with-extra-details", "Get a detailed pet record"
|
507
|
+
returns :code => 200, :desc => "Detailed info about the pet" do
|
508
|
+
param_group :pet
|
509
|
+
property :num_legs, Integer, :desc => "How many legs the pet has"
|
510
|
+
end
|
511
|
+
def show
|
512
|
+
render JSON({:pet_name => "Barkie", :animal_type => "iguana", :legs => 4})
|
513
|
+
end
|
514
|
+
|
515
|
+
# ------------------------------------------------
|
516
|
+
# Example of format #3 (array response):
|
517
|
+
# ------------------------------------------------
|
518
|
+
api :GET, "/pets", "Get all pet records"
|
519
|
+
returns :array_of => :pet, :code => 200, :desc => "All pets"
|
520
|
+
def index
|
521
|
+
render JSON([ {:pet_name => "Skippie", :animal_type => "kangaroo"},
|
522
|
+
{:pet_name => "Woofie", :animal_type => "cat"} ])
|
523
|
+
end
|
524
|
+
|
525
|
+
|
526
|
+
Note the use of the ``property`` keyword rather than ``param``. This is the
|
527
|
+
preferred mechanism for documenting response-only fields.
|
528
|
+
|
529
|
+
|
530
|
+
The Property keyword
|
531
|
+
::::::::::::::::::::::::::::::::::::::::::::::::
|
532
|
+
|
533
|
+
``property`` is very similar to ``param`` with the following differences:
|
534
|
+
|
535
|
+
* a ``property`` is ``:only_in => :response`` by default
|
536
|
+
|
537
|
+
* a ``property`` is ``:required => :true`` by default
|
538
|
+
|
539
|
+
* a ``property`` can be an ``:array_of`` objects
|
540
|
+
|
541
|
+
Example
|
542
|
+
_______
|
543
|
+
.. code:: ruby
|
544
|
+
|
545
|
+
property :example, :array_of => Hash do
|
546
|
+
property :number1, Integer
|
547
|
+
property :number2, Integer
|
548
|
+
end
|
549
|
+
|
550
|
+
|
551
|
+
Describing multiple return codes
|
552
|
+
::::::::::::::::::::::::::::::::::::::::::::::::
|
553
|
+
|
554
|
+
To describe multiple possible return codes, the ``:returns`` keyword can be repeated as many times as necessary
|
555
|
+
(once for each return code). Each one of the ``:returns`` entries can specify a different response format.
|
556
|
+
|
557
|
+
Example
|
558
|
+
_______
|
559
|
+
|
560
|
+
.. code:: ruby
|
561
|
+
|
562
|
+
api :GET, "/pets/:id/extra_info", "Get extra information about a pet"
|
563
|
+
returns :desc => "Found a pet" do
|
564
|
+
param_group :pet
|
565
|
+
property 'pet_history', Hash do
|
566
|
+
param_group :pet_history
|
567
|
+
end
|
568
|
+
end
|
569
|
+
returns :code => :unprocessable_entity, :desc => "Fleas were discovered on the pet" do
|
570
|
+
param_group :pet
|
571
|
+
property :num_fleas, Integer, :desc => "Number of fleas on this pet"
|
572
|
+
end
|
573
|
+
def show_extra_info
|
574
|
+
# ... implementation here
|
575
|
+
end
|
576
|
+
|
577
|
+
|
578
|
+
|
579
|
+
Reusing a param_group to describe inputs and outputs
|
580
|
+
::::::::::::::::::::::::::::::::::::::::::::::::::::
|
581
|
+
|
582
|
+
In many cases (such as CRUD implementations), the output from certain API calls is very similar - but not
|
583
|
+
identical - to the inputs of the same or other API calls.
|
584
|
+
|
585
|
+
If you already have a ``:param_group`` that defines the input to a `create` or `update` routine, it would be quite
|
586
|
+
frustrating to have to define a completely separate ``:param_group`` to describe the output of the `show` routine.
|
587
|
+
|
588
|
+
To address such situations, it is possible to define a single ``:param_group`` which combines ``param`` and ``property``
|
589
|
+
statements (as well as ``:only_in => :request`` / ``:only_in => :response``) to differentiate between fields that are
|
590
|
+
only expected in the request, only included in the response, or common to both.
|
591
|
+
|
592
|
+
This is somewhat analogous to the way `Action Aware params`_ work.
|
593
|
+
|
594
|
+
Example
|
595
|
+
_______
|
596
|
+
|
597
|
+
.. code:: ruby
|
598
|
+
|
599
|
+
def_param_group :user_record
|
600
|
+
param :name, String # this is commong to both the request and the response
|
601
|
+
param :force_update, [true, false], :only_in => :request # this does not show up in responses
|
602
|
+
property :last_login, String # this shows up only in the response
|
603
|
+
end
|
604
|
+
|
605
|
+
api :POST, "/users", "Create a user"
|
606
|
+
param_group :user_record # the :last_login field is not expected here, but :force_update is
|
607
|
+
def create
|
608
|
+
# ...
|
609
|
+
end
|
610
|
+
|
611
|
+
api :GET, "/users", "Create a user"
|
612
|
+
returns :array_of => :user_record # the :last_login field will be included in the response, but :force_update will not
|
613
|
+
def index
|
614
|
+
# ...
|
615
|
+
end
|
616
|
+
|
617
|
+
|
618
|
+
Embedded response descriptions
|
619
|
+
::::::::::::::::::::::::::::::
|
620
|
+
|
621
|
+
If the code creating JSON responses is encapsulated within dedicated classes, it can be more convenient to
|
622
|
+
place the response descriptions outside of the controller and embed them within the response generator.
|
623
|
+
|
624
|
+
To support such use cases, Apipie allows any class to provide a `describe_own_properties` class method which
|
625
|
+
returns a description of the properties such a class would expose. It is then possible to specify that
|
626
|
+
class in the `returns` statement instead of a `param_group`.
|
627
|
+
|
628
|
+
The `describe_own_properties` method is expected to return an array of `Apipie::prop` objects, each one
|
629
|
+
describing a single property.
|
630
|
+
|
631
|
+
Example
|
632
|
+
_______
|
633
|
+
|
634
|
+
.. code:: ruby
|
635
|
+
|
636
|
+
class Pet
|
637
|
+
# this method is automatically called by Apipie when Pet is specified as the returned object type
|
638
|
+
def self.describe_own_properties
|
639
|
+
[
|
640
|
+
Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
|
641
|
+
Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
|
642
|
+
Apipie::additional_properties(false) # this indicates that :pet_name and :animal_type are the only properties in the response
|
643
|
+
]
|
644
|
+
end
|
645
|
+
|
646
|
+
# this method w
|
647
|
+
def json
|
648
|
+
JSON({:pet_name => @name, :animal_type => @type })
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
|
653
|
+
class PetsController
|
654
|
+
api :GET, "/index", "Get all pets"
|
655
|
+
returns :array_of => Pet # Pet is a 'self-describing-class'
|
656
|
+
def index
|
657
|
+
# ...
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
|
662
|
+
A use case where this is very useful is when JSON generation is done using a reflection mechanism or some
|
663
|
+
other sort of declarative mechanism.
|
664
|
+
|
665
|
+
|
666
|
+
|
667
|
+
|
668
|
+
The `Apipie::prop` function expects the following inputs:
|
669
|
+
|
670
|
+
.. code:: ruby
|
671
|
+
|
672
|
+
Apipie::prop(<property-name>, <property-type>, <options-hash> [, <array of sub-properties>])
|
673
|
+
|
674
|
+
# property-name should be a symbol
|
675
|
+
#
|
676
|
+
# property-type can be any of the following strings:
|
677
|
+
# "integer": maps to a swagger "integer" with an "int32" format
|
678
|
+
# "long": maps to a swagger "integer" with an "int64" format
|
679
|
+
# "number": maps to a swagger "number"(no format specifier)
|
680
|
+
# "float": maps to a swagger "number" with a "float" format
|
681
|
+
# "double": maps to a swagger "number" with a "double" format
|
682
|
+
# "string": maps to a swagger "string" (no format specifier)
|
683
|
+
# "byte": maps to a swagger "string" with a "byte" format
|
684
|
+
# "binary": maps to a swagger "string" with a "binary" format
|
685
|
+
# "boolean": maps to a swagger "boolean" (no format specifier)
|
686
|
+
# "date": maps to a swagger "string" with a "date" format
|
687
|
+
# "dateTime": maps to a swagger "string" with a "date-time" format
|
688
|
+
# "password": maps to a swagger "string" with a "password" format
|
689
|
+
# "object": the property has sub-properties. include <array of sub-properties> in the call.
|
690
|
+
# (see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more information
|
691
|
+
# about the mapped swagger types)
|
692
|
+
#
|
693
|
+
# options-hash can include any of the options fields allowed in a :returns statement.
|
694
|
+
# additionally, it can include the ':is_array => true', in which case the property is understood to be
|
695
|
+
# an array of the described type.
|
696
|
+
|
697
|
+
|
698
|
+
|
699
|
+
To describe an embedded object:
|
700
|
+
|
701
|
+
.. code:: ruby
|
702
|
+
|
703
|
+
|
704
|
+
#
|
705
|
+
# PetWithMeasurements is a self-describing class with an embedded object
|
706
|
+
#
|
707
|
+
class PetWithMeasurements
|
708
|
+
def self.describe_own_properties
|
709
|
+
[
|
710
|
+
Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
|
711
|
+
Apipie::prop('animal_type', 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
|
712
|
+
Apipie::prop(:pet_measurements, 'object', {}, [
|
713
|
+
Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
|
714
|
+
Apipie::prop(:height, 'number', {:description => "Height in inches" }),
|
715
|
+
Apipie::prop(:num_legs, 'number', {:description => "Number of legs", :required => false }),
|
716
|
+
Apipie::additional_properties(false)
|
717
|
+
])
|
718
|
+
]
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
#
|
723
|
+
# PetWithManyMeasurements is a self-describing class with an embedded array of objects
|
724
|
+
#
|
725
|
+
class PetWithManyMeasurements
|
726
|
+
def self.describe_own_properties
|
727
|
+
[
|
728
|
+
Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
|
729
|
+
Apipie::prop(:many_pet_measurements, 'object', {is_array: true}, [
|
730
|
+
Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
|
731
|
+
Apipie::prop(:height, 'number', {:description => "Height in inches" }),
|
732
|
+
])
|
733
|
+
]
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
|
738
|
+
|
432
739
|
Concerns
|
433
740
|
--------
|
434
741
|
|
@@ -550,6 +857,9 @@ app_name
|
|
550
857
|
copyright
|
551
858
|
Copyright information (shown in page footer).
|
552
859
|
|
860
|
+
compress_examples
|
861
|
+
If ``true`` recorded examples are compressed using ``Zlib``. Useful for big test-suits.
|
862
|
+
|
553
863
|
doc_base_url
|
554
864
|
Documentation frontend base url.
|
555
865
|
|
@@ -1154,6 +1464,8 @@ If, for some complex cases, you need to generate/re-generate just part of the ca
|
|
1154
1464
|
use ``rake apipie:cache cache_part=index`` resp. ``rake apipie:cache cache_part=resources``
|
1155
1465
|
To generate it for different locations for further processing use ``rake apipie:cache OUT=/tmp/apipie_cache``.
|
1156
1466
|
|
1467
|
+
.. _Swagger:
|
1468
|
+
|
1157
1469
|
====================================
|
1158
1470
|
Static Swagger (OpenAPI 2.0) files
|
1159
1471
|
====================================
|
@@ -1236,6 +1548,11 @@ There are several configuration parameters that determine the structure of the g
|
|
1236
1548
|
|
1237
1549
|
If ``nil`` then then host field will not be included.
|
1238
1550
|
|
1551
|
+
``config.swagger_allow_additional_properties_in_response``
|
1552
|
+
If ``false`` (default): response descriptions in the generated swagger will include an ``additional-properties: false``
|
1553
|
+
field
|
1554
|
+
|
1555
|
+
If ``true``: the ``additional-properties: false`` field will not be included in response object descriptions
|
1239
1556
|
|
1240
1557
|
|
1241
1558
|
Known limitations of the current implementation
|
@@ -1246,6 +1563,7 @@ Known limitations of the current implementation
|
|
1246
1563
|
* It is not possible to specify the "consumed" content type on a per-method basis
|
1247
1564
|
* It is not possible to leverage all of the parameter type/format capabilities of swagger
|
1248
1565
|
* Only OpenAPI 2.0 is supported
|
1566
|
+
* Responses are defined inline and not as a $ref
|
1249
1567
|
|
1250
1568
|
====================================
|
1251
1569
|
Dynamic Swagger generation
|