apipie-rails 0.5.7 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|