swagger-docs 0.1.1 → 0.1.2
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +10 -0
- data/README.md +123 -12
- data/lib/swagger/docs/config.rb +1 -1
- data/lib/swagger/docs/dsl.rb +47 -3
- data/lib/swagger/docs/generator.rb +137 -80
- data/lib/swagger/docs/impotent_methods.rb +3 -0
- data/lib/swagger/docs/methods.rb +10 -6
- data/lib/swagger/docs/version.rb +1 -1
- data/spec/fixtures/controllers/sample_controller.rb +14 -0
- data/spec/lib/swagger/docs/generator_spec.rb +132 -89
- data/spec/spec_helper.rb +30 -5
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +1 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9940ad082299dc2d0d6cb34a3e7c1336a37e0c8b
|
4
|
+
data.tar.gz: 9f75192abe6f35735aea5b4948482211177b5cf0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d1a4e4f8a4c83ed76b547414ff6c1ac1887d3570bcb43b90b665d7e8ca9c97ee7f5de6cdd097d5c790bac0a8fdf2dbd53b04c72ae892e85c415b0757bdd444b
|
7
|
+
data.tar.gz: abba4ab15746a0ec3e1b8c8b2bbe78f35c62438289ed53641b1b682c5204eb971f7b6c67d67103a29093c5eb5eb49025a6194012b6564f07cdc4229c0e44b875
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.1.2
|
2
|
+
- Add suport for Swagger models
|
3
|
+
- Use ActionControlller::Base instead of ApplicationController. fixes #27
|
4
|
+
- Status codes for response
|
5
|
+
- Path generation fixes #26 @stevschmid
|
6
|
+
- Ignore path filtering when no params are set
|
7
|
+
- Add param_list helper for generating enums/lists
|
8
|
+
- Improve structure of generator class - break up large methods
|
9
|
+
- Fix the destination path of the resource files #30
|
10
|
+
|
1
11
|
## 0.1.1
|
2
12
|
- Add support for Rails engines (@fotinakis)
|
3
13
|
- Filter out path parameters if the parameter is not in the path (@stevschmid)
|
data/README.md
CHANGED
@@ -42,11 +42,11 @@ Swagger::Docs::Config.register_apis({
|
|
42
42
|
# the extension used for the API
|
43
43
|
:api_extension_type => :json,
|
44
44
|
# the output location where your .json files are written to
|
45
|
-
:api_file_path => "public/api/v1/",
|
46
|
-
# the URL base path to your API
|
47
|
-
:base_path => "http://api.somedomain.com",
|
45
|
+
:api_file_path => "public/api/v1/",
|
46
|
+
# the URL base path to your API
|
47
|
+
:base_path => "http://api.somedomain.com",
|
48
48
|
# if you want to delete all .json files at each generation
|
49
|
-
:clean_directory => false
|
49
|
+
:clean_directory => false
|
50
50
|
}
|
51
51
|
})
|
52
52
|
```
|
@@ -109,8 +109,9 @@ class Api::V1::UsersController < ApplicationController
|
|
109
109
|
swagger_api :index do
|
110
110
|
summary "Fetches all User items"
|
111
111
|
param :query, :page, :integer, :optional, "Page number"
|
112
|
+
param :path, :nested_id, :integer, :optional, "Team Id"
|
112
113
|
response :unauthorized
|
113
|
-
response :not_acceptable
|
114
|
+
response :not_acceptable, "The request you made is not acceptable"
|
114
115
|
response :requested_range_not_satisfiable
|
115
116
|
end
|
116
117
|
|
@@ -127,6 +128,7 @@ class Api::V1::UsersController < ApplicationController
|
|
127
128
|
param :form, :first_name, :string, :required, "First name"
|
128
129
|
param :form, :last_name, :string, :required, "Last name"
|
129
130
|
param :form, :email, :string, :required, "Email address"
|
131
|
+
param_list :form, :role, :string, :required, "Role", [ "admin", "superadmin", "user" ]
|
130
132
|
response :unauthorized
|
131
133
|
response :not_acceptable
|
132
134
|
end
|
@@ -137,6 +139,7 @@ class Api::V1::UsersController < ApplicationController
|
|
137
139
|
param :form, :first_name, :string, :optional, "First name"
|
138
140
|
param :form, :last_name, :string, :optional, "Last name"
|
139
141
|
param :form, :email, :string, :optional, "Email address"
|
142
|
+
param :form, :tag, :Tag, :required, "Tag object"
|
140
143
|
response :unauthorized
|
141
144
|
response :not_found
|
142
145
|
response :not_acceptable
|
@@ -149,9 +152,51 @@ class Api::V1::UsersController < ApplicationController
|
|
149
152
|
response :not_found
|
150
153
|
end
|
151
154
|
|
155
|
+
# Support for Swagger complex types:
|
156
|
+
# https://github.com/wordnik/swagger-core/wiki/Datatypes#wiki-complex-types
|
157
|
+
swagger_model :Tag do
|
158
|
+
description "A Tag object."
|
159
|
+
property :id, :integer, :required, "User Id"
|
160
|
+
property :name, :string, :optional, "Name"
|
161
|
+
end
|
162
|
+
|
152
163
|
end
|
153
164
|
```
|
154
165
|
|
166
|
+
### DSL Methods
|
167
|
+
|
168
|
+
<table>
|
169
|
+
<thead>
|
170
|
+
<tr>
|
171
|
+
<th>Method</th>
|
172
|
+
<th>Description</th>
|
173
|
+
</tr>
|
174
|
+
</thead>
|
175
|
+
<tbody>
|
176
|
+
|
177
|
+
<tr>
|
178
|
+
<td>summary</td>
|
179
|
+
<td>The summary of the API</td>
|
180
|
+
</tr>
|
181
|
+
|
182
|
+
<tr>
|
183
|
+
<td>param</td>
|
184
|
+
<td>Standard API Parameter</td>
|
185
|
+
</tr>
|
186
|
+
|
187
|
+
<tr>
|
188
|
+
<td>param_list</td>
|
189
|
+
<td>Standard API Enum/List parameter.</td>
|
190
|
+
</tr>
|
191
|
+
|
192
|
+
<tr>
|
193
|
+
<td>response</td>
|
194
|
+
<td>Takes a symbol or status code and passes it to `Rack::Utils.status_code`. The current list of status codes can be seen here: https://github.com/rack/rack/blob/master/lib/rack/utils.rb. An optional message can be added.</td>
|
195
|
+
</tr>
|
196
|
+
|
197
|
+
</tbody>
|
198
|
+
</table>
|
199
|
+
|
155
200
|
### Run rake task to generate docs
|
156
201
|
|
157
202
|
```
|
@@ -160,7 +205,7 @@ rake swagger:docs
|
|
160
205
|
|
161
206
|
Swagger-ui JSON files should now be present in your api_file_path (e.g. ./public/api/v1)
|
162
207
|
|
163
|
-
### Sample
|
208
|
+
### Sample
|
164
209
|
|
165
210
|
A sample Rails application where you can run the above rake command and view the output in swagger-ui can be found here:
|
166
211
|
|
@@ -173,8 +218,8 @@ https://github.com/richhollis/swagger-docs-sample
|
|
173
218
|
|
174
219
|
#### Inheriting from a custom Api controller
|
175
220
|
|
176
|
-
By default swagger-docs is applied to controllers inheriting from ApplicationController.
|
177
|
-
If this is not the case for your application, use this snippet in your initializer
|
221
|
+
By default swagger-docs is applied to controllers inheriting from ApplicationController.
|
222
|
+
If this is not the case for your application, use this snippet in your initializer
|
178
223
|
_before_ calling Swagger::Docs::Config#register_apis(...).
|
179
224
|
|
180
225
|
```ruby
|
@@ -194,7 +239,6 @@ class Swagger::Docs::Config
|
|
194
239
|
end
|
195
240
|
```
|
196
241
|
|
197
|
-
=======
|
198
242
|
#### Transforming the `path` variable
|
199
243
|
|
200
244
|
Swagger allows a distinction between the API documentation server and the hosted API
|
@@ -253,7 +297,7 @@ users.json output:
|
|
253
297
|
{
|
254
298
|
"apiVersion": "1.0",
|
255
299
|
"swaggerVersion": "1.2",
|
256
|
-
"basePath": "/api/v1",
|
300
|
+
"basePath": "http://api.somedomain.com/api/v1/",
|
257
301
|
"resourcePath": "/users",
|
258
302
|
"apis": [
|
259
303
|
{
|
@@ -277,7 +321,47 @@ users.json output:
|
|
277
321
|
},
|
278
322
|
{
|
279
323
|
"code": 406,
|
280
|
-
"message": "
|
324
|
+
"message": "The request you made is not acceptable"
|
325
|
+
},
|
326
|
+
{
|
327
|
+
"code": 416,
|
328
|
+
"message": "Requested Range Not Satisfiable"
|
329
|
+
}
|
330
|
+
],
|
331
|
+
"method": "get",
|
332
|
+
"nickname": "Api::V1::Users#index"
|
333
|
+
}
|
334
|
+
]
|
335
|
+
},
|
336
|
+
{
|
337
|
+
"path": "nested/{nested_id}/sample",
|
338
|
+
"operations": [
|
339
|
+
{
|
340
|
+
"summary": "Fetches all User items",
|
341
|
+
"parameters": [
|
342
|
+
{
|
343
|
+
"paramType": "query",
|
344
|
+
"name": "page",
|
345
|
+
"type": "integer",
|
346
|
+
"description": "Page number",
|
347
|
+
"required": false
|
348
|
+
},
|
349
|
+
{
|
350
|
+
"paramType": "path",
|
351
|
+
"name": "nested_id",
|
352
|
+
"type": "integer",
|
353
|
+
"description": "Team Id",
|
354
|
+
"required": false
|
355
|
+
}
|
356
|
+
],
|
357
|
+
"responseMessages": [
|
358
|
+
{
|
359
|
+
"code": 401,
|
360
|
+
"message": "Unauthorized"
|
361
|
+
},
|
362
|
+
{
|
363
|
+
"code": 406,
|
364
|
+
"message": "The request you made is not acceptable"
|
281
365
|
},
|
282
366
|
{
|
283
367
|
"code": 416,
|
@@ -398,6 +482,13 @@ users.json output:
|
|
398
482
|
"type": "string",
|
399
483
|
"description": "Email address",
|
400
484
|
"required": false
|
485
|
+
},
|
486
|
+
{
|
487
|
+
"paramType": "form",
|
488
|
+
"name": "tag",
|
489
|
+
"type": "Tag",
|
490
|
+
"description": "Tag object",
|
491
|
+
"required": true
|
401
492
|
}
|
402
493
|
],
|
403
494
|
"responseMessages": [
|
@@ -448,7 +539,27 @@ users.json output:
|
|
448
539
|
}
|
449
540
|
]
|
450
541
|
}
|
451
|
-
]
|
542
|
+
],
|
543
|
+
"models": {
|
544
|
+
"Tag": {
|
545
|
+
"id": "Tag",
|
546
|
+
"required": [
|
547
|
+
"id"
|
548
|
+
],
|
549
|
+
"properties": {
|
550
|
+
"id": {
|
551
|
+
"type": "integer",
|
552
|
+
"description": "User Id"
|
553
|
+
},
|
554
|
+
"name": {
|
555
|
+
"type": "string",
|
556
|
+
"description": "Name",
|
557
|
+
"foo": "test"
|
558
|
+
}
|
559
|
+
},
|
560
|
+
"description": "A Tag object."
|
561
|
+
}
|
562
|
+
}
|
452
563
|
}
|
453
564
|
```
|
454
565
|
|
data/lib/swagger/docs/config.rb
CHANGED
@@ -2,7 +2,7 @@ module Swagger
|
|
2
2
|
module Docs
|
3
3
|
class Config
|
4
4
|
class << self
|
5
|
-
def base_api_controller;
|
5
|
+
def base_api_controller; ActionController::Base end
|
6
6
|
def base_application; Rails.application end
|
7
7
|
def register_apis(versions)
|
8
8
|
base_api_controller.send(:include, ImpotentMethods)
|
data/lib/swagger/docs/dsl.rb
CHANGED
@@ -2,10 +2,10 @@ module Swagger
|
|
2
2
|
module Docs
|
3
3
|
class SwaggerDSL
|
4
4
|
# http://stackoverflow.com/questions/5851127/change-the-context-binding-inside-a-block-in-ruby/5851325#5851325
|
5
|
-
def self.call(action, caller, &
|
6
|
-
# Create a new
|
5
|
+
def self.call(action, caller, &block)
|
6
|
+
# Create a new SwaggerDSL instance, and instance_eval the block to it
|
7
7
|
instance = new
|
8
|
-
instance.instance_eval(&
|
8
|
+
instance.instance_eval(&block)
|
9
9
|
# Now return all of the set instance variables as a Hash
|
10
10
|
instance.instance_variables.inject({}) { |result_hash, instance_variable|
|
11
11
|
result_hash[instance_variable] = instance.instance_variable_get(instance_variable)
|
@@ -38,6 +38,12 @@ module Swagger
|
|
38
38
|
:description => description, :required => required == :required ? true : false}.merge(hash)
|
39
39
|
end
|
40
40
|
|
41
|
+
# helper method to generate enums
|
42
|
+
def param_list(param_type, name, type, required, description = nil, allowed_values = [], hash = {})
|
43
|
+
hash.merge!({allowable_values: {value_type: "LIST", values: allowed_values}})
|
44
|
+
param(param_type, name, type, required, description = nil, hash)
|
45
|
+
end
|
46
|
+
|
41
47
|
def response_messages
|
42
48
|
@response_messages ||= []
|
43
49
|
end
|
@@ -52,5 +58,43 @@ module Swagger
|
|
52
58
|
response_messages.sort_by!{|i| i[:code]}
|
53
59
|
end
|
54
60
|
end
|
61
|
+
|
62
|
+
class SwaggerModelDSL
|
63
|
+
attr_accessor :id
|
64
|
+
|
65
|
+
# http://stackoverflow.com/questions/5851127/change-the-context-binding-inside-a-block-in-ruby/5851325#5851325
|
66
|
+
def self.call(model_name, caller, &block)
|
67
|
+
# Create a new SwaggerModelDSL instance, and instance_eval the block to it
|
68
|
+
instance = new
|
69
|
+
instance.instance_eval(&block)
|
70
|
+
instance.id = model_name
|
71
|
+
# Now return all of the set instance variables as a Hash
|
72
|
+
instance.instance_variables.inject({}) { |result_hash, instance_var_name|
|
73
|
+
key = instance_var_name[1..-1].to_sym # Strip prefixed @ sign.
|
74
|
+
result_hash[key] = instance.instance_variable_get(instance_var_name)
|
75
|
+
result_hash # Gotta have the block return the result_hash
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def properties
|
80
|
+
@properties ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def required
|
84
|
+
@required ||= []
|
85
|
+
end
|
86
|
+
|
87
|
+
def description(description)
|
88
|
+
@description = description
|
89
|
+
end
|
90
|
+
|
91
|
+
def property(name, type, required, description = nil, hash={})
|
92
|
+
properties[name] = {
|
93
|
+
type: type,
|
94
|
+
description: description,
|
95
|
+
}.merge!(hash)
|
96
|
+
self.required << name if (required == :required ? true : false)
|
97
|
+
end
|
98
|
+
end
|
55
99
|
end
|
56
100
|
end
|
@@ -12,6 +12,63 @@ module Swagger
|
|
12
12
|
|
13
13
|
class << self
|
14
14
|
|
15
|
+
def set_real_methods
|
16
|
+
Config.base_api_controller.send(:include, Methods) # replace impotent methods with live ones
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_docs(apis = nil)
|
20
|
+
apis ||= Config.registered_apis
|
21
|
+
results = {}
|
22
|
+
set_real_methods
|
23
|
+
unless apis.empty?
|
24
|
+
apis.each do |api_version,config|
|
25
|
+
config.reverse_merge!(DEFAULT_CONFIG)
|
26
|
+
results[api_version] = write_doc(api_version, config)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
results[DEFAULT_VER] = write_doc(DEFAULT_VER, DEFAULT_CONFIG)
|
30
|
+
end
|
31
|
+
results
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_doc(api_version, config)
|
35
|
+
settings = get_settings(api_version, config)
|
36
|
+
|
37
|
+
create_output_paths(settings[:api_file_path])
|
38
|
+
clean_output_paths(settings[:api_file_path]) if config[:clean_directory] || false
|
39
|
+
|
40
|
+
root = { :api_version => api_version, :swagger_version => "1.2", :base_path => settings[:base_path] + "/", :apis => []}
|
41
|
+
results = {:processed => [], :skipped => []}
|
42
|
+
|
43
|
+
get_route_paths(settings[:controller_base_path]).each do |path|
|
44
|
+
ret = process_path(path, root, config, settings)
|
45
|
+
results[ret[:action]] << ret
|
46
|
+
if ret[:action] == :processed
|
47
|
+
create_resource_file(ret[:path], ret[:apis], ret[:models], settings, root, config)
|
48
|
+
debased_path = get_debased_path(ret[:path], settings[:controller_base_path])
|
49
|
+
resource_api = {
|
50
|
+
path: "#{Config.transform_path(trim_leading_slash(debased_path))}.{format}",
|
51
|
+
description: ret[:klass].swagger_config[:description]
|
52
|
+
}
|
53
|
+
root[:apis] << resource_api
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
camelize_keys_deep!(root)
|
58
|
+
write_to_file("#{settings[:api_file_path]}/api-docs.json", root, config)
|
59
|
+
results
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def transform_spec_to_api_path(spec, controller_base_path, extension)
|
65
|
+
api_path = spec.to_s.dup
|
66
|
+
api_path.gsub!('(.:format)', extension ? ".#{extension}" : '')
|
67
|
+
api_path.gsub!(/:(\w+)/, '{\1}')
|
68
|
+
api_path.gsub!(controller_base_path, '')
|
69
|
+
trim_slashes(api_path)
|
70
|
+
end
|
71
|
+
|
15
72
|
def camelize_keys_deep!(h)
|
16
73
|
h.keys.each do |k|
|
17
74
|
ks = k.to_s.camelize(:lower)
|
@@ -26,107 +83,108 @@ module Swagger
|
|
26
83
|
end
|
27
84
|
end
|
28
85
|
|
29
|
-
def get_api_path(spec, extension)
|
30
|
-
extension = ".#{extension}" if extension
|
31
|
-
path_api = trim_leading_slash(spec.to_s.gsub("(.:format)", extension.to_s))
|
32
|
-
parts_new = []
|
33
|
-
path_api.split("/").each do |path_part|
|
34
|
-
part = path_part
|
35
|
-
if part[0] == ":"
|
36
|
-
part[0] = "{"
|
37
|
-
part << "}"
|
38
|
-
end
|
39
|
-
parts_new << part
|
40
|
-
end
|
41
|
-
path_api = parts_new*"/"
|
42
|
-
end
|
43
|
-
|
44
86
|
def trim_leading_slash(str)
|
45
87
|
return str if !str
|
46
|
-
|
47
|
-
str[1..-1]
|
88
|
+
str.gsub(/\A\/+/, '')
|
48
89
|
end
|
49
90
|
|
50
91
|
def trim_trailing_slash(str)
|
51
92
|
return str if !str
|
52
|
-
|
53
|
-
str[0..-2]
|
93
|
+
str.gsub(/\/+\z/, '')
|
54
94
|
end
|
55
95
|
|
56
96
|
def trim_slashes(str)
|
57
97
|
trim_leading_slash(trim_trailing_slash(str))
|
58
98
|
end
|
59
99
|
|
60
|
-
def
|
61
|
-
|
100
|
+
def get_debased_path(path, controller_base_path)
|
101
|
+
path.gsub("#{controller_base_path}", "")
|
62
102
|
end
|
63
103
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
else
|
74
|
-
results[DEFAULT_VER] = write_doc(DEFAULT_VER, DEFAULT_CONFIG)
|
104
|
+
def process_path(path, root, config, settings)
|
105
|
+
return {action: empty} if path.empty?
|
106
|
+
klass = "#{path.to_s.camelize}Controller".constantize
|
107
|
+
return {action: :skipped, path: path} if !klass.methods.include?(:swagger_config) or !klass.swagger_config[:controller]
|
108
|
+
apis, models = [], {}
|
109
|
+
Config.base_application.routes.routes.select{|i| i.defaults[:controller] == path}.each do |route|
|
110
|
+
ret = get_route_path_apis(path, route, klass, settings, config)
|
111
|
+
apis = apis + ret[:apis]
|
112
|
+
models.merge!(ret[:models])
|
75
113
|
end
|
76
|
-
|
114
|
+
{action: :processed, path: path, apis: apis, models: models, klass: klass}
|
77
115
|
end
|
78
116
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
117
|
+
def create_resource_file(path, apis, models, settings, root, config)
|
118
|
+
debased_path = get_debased_path(path, settings[:controller_base_path])
|
119
|
+
demod = "#{debased_path.to_s.camelize}".demodulize.camelize.underscore
|
120
|
+
resource_path = trim_leading_slash(debased_path.to_s.underscore)
|
121
|
+
resource = root.merge({:resource_path => "#{demod}", :apis => apis})
|
122
|
+
camelize_keys_deep!(resource)
|
123
|
+
# Add the already-normalized models to the resource.
|
124
|
+
resource = resource.merge({:models => models}) if models.present?
|
125
|
+
# write controller resource file
|
126
|
+
write_to_file(File.join(settings[:api_file_path], "#{resource_path}.json"), resource, config)
|
127
|
+
end
|
85
128
|
|
86
|
-
|
87
|
-
|
88
|
-
|
129
|
+
def get_route_path_apis(path, route, klass, settings, config)
|
130
|
+
models, apis = {}, []
|
131
|
+
action = route.defaults[:action]
|
132
|
+
verb = route.verb.source.to_s.delete('$'+'^').downcase.to_sym
|
133
|
+
return apis if !operations = klass.swagger_actions[action.to_sym]
|
134
|
+
operations = Hash[operations.map {|k, v| [k.to_s.gsub("@","").to_sym, v.respond_to?(:deep_dup) ? v.deep_dup : v.dup] }] # rename :@instance hash keys
|
135
|
+
operations[:method] = verb
|
136
|
+
operations[:nickname] = "#{path.camelize}##{action}"
|
137
|
+
|
138
|
+
api_path = transform_spec_to_api_path(route.path.spec, settings[:controller_base_path], config[:api_extension_type])
|
139
|
+
operations[:parameters] = filter_path_params(api_path, operations[:parameters]) if operations[:parameters]
|
140
|
+
|
141
|
+
apis << {:path => api_path, :operations => [operations]}
|
142
|
+
models = get_klass_models(klass)
|
143
|
+
|
144
|
+
{apis: apis, models: models}
|
145
|
+
end
|
146
|
+
|
147
|
+
def get_klass_models(klass)
|
148
|
+
models = {}
|
149
|
+
# Add any declared models to the root of the resource.
|
150
|
+
klass.swagger_models.each do |model_name, model|
|
151
|
+
formatted_model = {
|
152
|
+
id: model[:id],
|
153
|
+
required: model[:required],
|
154
|
+
properties: model[:properties],
|
155
|
+
}
|
156
|
+
formatted_model[:description] = model[:description] if model[:description]
|
157
|
+
models[model[:id]] = formatted_model
|
158
|
+
end
|
159
|
+
models
|
160
|
+
end
|
89
161
|
|
162
|
+
def get_settings(api_version, config)
|
163
|
+
base_path = trim_trailing_slash(config[:base_path] || "")
|
164
|
+
controller_base_path = trim_leading_slash(config[:controller_base_path] || "")
|
90
165
|
base_path += "/#{controller_base_path}" unless controller_base_path.empty?
|
91
|
-
|
92
|
-
|
166
|
+
api_file_path = config[:api_file_path]
|
167
|
+
settings = {
|
168
|
+
base_path: base_path,
|
169
|
+
controller_base_path: controller_base_path,
|
170
|
+
api_file_path: api_file_path
|
171
|
+
}.freeze
|
172
|
+
end
|
93
173
|
|
174
|
+
def get_route_paths(controller_base_path)
|
94
175
|
paths = Config.base_application.routes.routes.map{|i| "#{i.defaults[:controller]}" }
|
95
|
-
paths
|
96
|
-
|
97
|
-
next if path.empty?
|
98
|
-
klass = "#{path.to_s.camelize}Controller".constantize
|
99
|
-
if !klass.methods.include?(:swagger_config) or !klass.swagger_config[:controller]
|
100
|
-
results[:skipped] << path
|
101
|
-
next
|
102
|
-
end
|
103
|
-
apis = []
|
104
|
-
debased_path = path.gsub("#{controller_base_path}", "")
|
105
|
-
Config.base_application.routes.routes.select{|i| i.defaults[:controller] == path}.each do |route|
|
106
|
-
action = route.defaults[:action]
|
107
|
-
verb = route.verb.source.to_s.delete('$'+'^').downcase.to_sym
|
108
|
-
next if !operations = klass.swagger_actions[action.to_sym]
|
109
|
-
operations = Hash[operations.map {|k, v| [k.to_s.gsub("@","").to_sym, v.respond_to?(:deep_dup) ? v.deep_dup : v.dup] }] # rename :@instance hash keys
|
110
|
-
operations[:method] = verb
|
111
|
-
operations[:nickname] = "#{path.camelize}##{action}"
|
112
|
-
api_path = trim_slashes(get_api_path(trim_leading_slash(route.path.spec.to_s), config[:api_extension_type]).gsub("#{controller_base_path}",""))
|
113
|
-
operations[:parameters] = filter_path_params(api_path, operations[:parameters])
|
114
|
-
apis << {:path => api_path, :operations => [operations]}
|
115
|
-
end
|
116
|
-
demod = "#{debased_path.to_s.camelize}".demodulize.camelize.underscore
|
117
|
-
resource = header.merge({:resource_path => "#{demod}", :apis => apis})
|
118
|
-
camelize_keys_deep!(resource)
|
119
|
-
# write controller resource file
|
120
|
-
write_to_file "#{api_file_path}/#{demod}.json", resource, config
|
121
|
-
# append resource to resources array (for writing out at end)
|
122
|
-
resources[:apis] << {path: "#{Config.transform_path(trim_leading_slash(debased_path))}.{format}", description: klass.swagger_config[:description]}
|
123
|
-
results[:processed] << path
|
124
|
-
end
|
125
|
-
# write master resource file
|
126
|
-
camelize_keys_deep!(resources)
|
176
|
+
paths.uniq.select{|i| i.start_with?(controller_base_path)}
|
177
|
+
end
|
127
178
|
|
128
|
-
|
129
|
-
|
179
|
+
def create_output_paths(api_file_path)
|
180
|
+
FileUtils.mkdir_p(api_file_path) # recursively create out output path
|
181
|
+
end
|
182
|
+
|
183
|
+
def clean_output_paths(api_file_path)
|
184
|
+
Dir.foreach(api_file_path) do |f|
|
185
|
+
fn = File.join(api_file_path, f)
|
186
|
+
File.delete(fn) if !File.directory?(fn) and File.extname(fn) == '.json'
|
187
|
+
end
|
130
188
|
end
|
131
189
|
|
132
190
|
def write_to_file(path, structure, config={})
|
@@ -134,11 +192,10 @@ module Swagger
|
|
134
192
|
when :pretty; JSON.pretty_generate structure
|
135
193
|
else; structure.to_json
|
136
194
|
end
|
195
|
+
FileUtils.mkdir_p File.dirname(path)
|
137
196
|
File.open(path, 'w') { |file| file.write content }
|
138
197
|
end
|
139
198
|
|
140
|
-
private
|
141
|
-
|
142
199
|
def filter_path_params(path, params)
|
143
200
|
params.reject do |param|
|
144
201
|
param_as_variable = "{#{param[:name]}}"
|
data/lib/swagger/docs/methods.rb
CHANGED
@@ -11,14 +11,14 @@ module Swagger
|
|
11
11
|
swagger_config[:description] = description
|
12
12
|
end
|
13
13
|
|
14
|
-
def swagger_model(model)
|
15
|
-
swagger_config[:model] = model
|
16
|
-
end
|
17
|
-
|
18
14
|
def swagger_actions
|
19
15
|
@swagger_dsl
|
20
16
|
end
|
21
17
|
|
18
|
+
def swagger_models
|
19
|
+
@swagger_model_dsls ||= {}
|
20
|
+
end
|
21
|
+
|
22
22
|
def swagger_config
|
23
23
|
@swagger_config ||= {}
|
24
24
|
end
|
@@ -27,12 +27,16 @@ module Swagger
|
|
27
27
|
|
28
28
|
def swagger_api(action, &block)
|
29
29
|
@swagger_dsl ||= {}
|
30
|
-
controller_action = "#{name}##{action} #{self.class}"
|
31
30
|
return if @swagger_dsl[action]
|
32
|
-
route = Swagger::Docs::Config.base_application.routes.routes.select{|i| "#{i.defaults[:controller].to_s.camelize}Controller##{i.defaults[:action]}" == controller_action }.first
|
33
31
|
dsl = SwaggerDSL.call(action, self, &block)
|
34
32
|
@swagger_dsl[action] = dsl
|
35
33
|
end
|
34
|
+
|
35
|
+
def swagger_model(model_name, &block)
|
36
|
+
@swagger_model_dsls ||= {}
|
37
|
+
model_dsl = SwaggerModelDSL.call(model_name, self, &block)
|
38
|
+
@swagger_model_dsls[model_name] = model_dsl
|
39
|
+
end
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
data/lib/swagger/docs/version.rb
CHANGED
@@ -27,6 +27,7 @@ module Api
|
|
27
27
|
param :form, :first_name, :string, :required, "First name"
|
28
28
|
param :form, :last_name, :string, :required, "Last name"
|
29
29
|
param :form, :email, :string, :required, "Email address"
|
30
|
+
param_list :form, :role, :string, :required, "Role", [ "admin", "superadmin", "user" ]
|
30
31
|
response :unauthorized
|
31
32
|
response :not_acceptable
|
32
33
|
end
|
@@ -37,6 +38,7 @@ module Api
|
|
37
38
|
param :form, :first_name, :string, :optional, "First name"
|
38
39
|
param :form, :last_name, :string, :optional, "Last name"
|
39
40
|
param :form, :email, :string, :optional, "Email address"
|
41
|
+
param :form, :tag, :Tag, :required, "Tag object"
|
40
42
|
response :unauthorized
|
41
43
|
response :not_found
|
42
44
|
response :not_acceptable
|
@@ -49,6 +51,18 @@ module Api
|
|
49
51
|
response :not_found
|
50
52
|
end
|
51
53
|
|
54
|
+
# a method that intentionally has no parameters
|
55
|
+
swagger_api :new do
|
56
|
+
summary "Builds a new User item"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Support for Swagger complex types:
|
60
|
+
# https://github.com/wordnik/swagger-core/wiki/Datatypes#wiki-complex-types
|
61
|
+
swagger_model :Tag do
|
62
|
+
description "A Tag object."
|
63
|
+
property :id, :integer, :required, "User Id"
|
64
|
+
property :name, :string, :optional, "Name", foo: "test"
|
65
|
+
end
|
52
66
|
end
|
53
67
|
end
|
54
68
|
end
|
@@ -5,19 +5,9 @@ describe Swagger::Docs::Generator do
|
|
5
5
|
require "fixtures/controllers/application_controller"
|
6
6
|
require "fixtures/controllers/ignored_controller"
|
7
7
|
|
8
|
-
def generate(config)
|
9
|
-
Swagger::Docs::Generator::write_docs(config)
|
10
|
-
end
|
11
|
-
|
12
|
-
def stub_route(verb, action, controller, spec)
|
13
|
-
double("route", :verb => double("verb", :source => verb),
|
14
|
-
:defaults => {:action => action, :controller => controller},
|
15
|
-
:path => double("path", :spec => spec)
|
16
|
-
)
|
17
|
-
end
|
18
|
-
|
19
8
|
before(:each) do
|
20
|
-
FileUtils.rm_rf(
|
9
|
+
FileUtils.rm_rf(tmp_dir)
|
10
|
+
stub_const('ActionController::Base', ApplicationController)
|
21
11
|
end
|
22
12
|
|
23
13
|
let(:routes) {[
|
@@ -27,13 +17,18 @@ describe Swagger::Docs::Generator do
|
|
27
17
|
stub_route("^POST$", "create", "api/v1/sample", "/api/v1/sample(.:format)"),
|
28
18
|
stub_route("^GET$", "show", "api/v1/sample", "/api/v1/sample/:id(.:format)"),
|
29
19
|
stub_route("^PUT$", "update", "api/v1/sample", "/api/v1/sample/:id(.:format)"),
|
30
|
-
stub_route("^DELETE$", "destroy", "api/v1/sample", "/api/v1/sample/:id(.:format)")
|
20
|
+
stub_route("^DELETE$", "destroy", "api/v1/sample", "/api/v1/sample/:id(.:format)"),
|
21
|
+
stub_route("^GET$", "new", "api/v1/sample", "/api/v1/sample/new(.:format)") # no parameters for this method
|
31
22
|
]}
|
32
23
|
|
24
|
+
let(:tmp_dir) { Pathname.new('/tmp/swagger-docs/') }
|
25
|
+
let(:file_resources) { tmp_dir + 'api-docs.json' }
|
26
|
+
let(:file_resource) { tmp_dir + 'api/v1/sample.json' }
|
27
|
+
|
33
28
|
context "without controller base path" do
|
34
|
-
let(:config) {
|
29
|
+
let(:config) {
|
35
30
|
{
|
36
|
-
DEFAULT_VER => {:api_file_path => "#{
|
31
|
+
DEFAULT_VER => {:api_file_path => "#{tmp_dir}", :base_path => "http://api.no.where"}
|
37
32
|
}
|
38
33
|
}
|
39
34
|
before(:each) do
|
@@ -43,7 +38,7 @@ describe Swagger::Docs::Generator do
|
|
43
38
|
generate(config)
|
44
39
|
end
|
45
40
|
context "resources files" do
|
46
|
-
let(:resources) {
|
41
|
+
let(:resources) { file_resources.read }
|
47
42
|
let(:response) { JSON.parse(resources) }
|
48
43
|
it "writes basePath correctly" do
|
49
44
|
expect(response["basePath"]).to eq "http://api.no.where/"
|
@@ -56,7 +51,7 @@ describe Swagger::Docs::Generator do
|
|
56
51
|
end
|
57
52
|
end
|
58
53
|
context "resource file" do
|
59
|
-
let(:resource) {
|
54
|
+
let(:resource) { file_resource.read }
|
60
55
|
let(:response) { JSON.parse(resource) }
|
61
56
|
let(:first) { response["apis"].first }
|
62
57
|
let(:operations) { first["operations"] }
|
@@ -68,7 +63,7 @@ describe Swagger::Docs::Generator do
|
|
68
63
|
expect(response["resourcePath"]).to eq "sample"
|
69
64
|
end
|
70
65
|
it "writes out expected api count" do
|
71
|
-
expect(response["apis"].count).to eq
|
66
|
+
expect(response["apis"].count).to eq 7
|
72
67
|
end
|
73
68
|
context "first api" do
|
74
69
|
#"apis":[{"path":" /sample","operations":[{"summary":"Fetches all User items"
|
@@ -82,9 +77,10 @@ describe Swagger::Docs::Generator do
|
|
82
77
|
|
83
78
|
context "with controller base path" do
|
84
79
|
let(:config) { Swagger::Docs::Config.register_apis({
|
85
|
-
|
80
|
+
DEFAULT_VER => {:controller_base_path => "api/v1", :api_file_path => "#{tmp_dir}", :base_path => "http://api.no.where"}
|
86
81
|
})}
|
87
|
-
|
82
|
+
let(:file_resource) { tmp_dir + 'sample.json' }
|
83
|
+
before(:each) do
|
88
84
|
Rails.stub_chain(:application, :routes, :routes).and_return(routes)
|
89
85
|
Swagger::Docs::Generator.set_real_methods
|
90
86
|
require "fixtures/controllers/sample_controller"
|
@@ -92,16 +88,16 @@ describe Swagger::Docs::Generator do
|
|
92
88
|
|
93
89
|
context "test suite initialization" do
|
94
90
|
it "the resources file does not exist" do
|
95
|
-
expect(
|
91
|
+
expect(file_resource).to_not exist
|
96
92
|
end
|
97
93
|
it "the resource file does not exist" do
|
98
|
-
expect(
|
94
|
+
expect(file_resource).to_not exist
|
99
95
|
end
|
100
96
|
end
|
101
97
|
|
102
98
|
describe "#write_docs" do
|
103
99
|
context "no apis registered" do
|
104
|
-
before(:each) do
|
100
|
+
before(:each) do
|
105
101
|
Swagger::Docs::Config.register_apis({})
|
106
102
|
end
|
107
103
|
it "generates using default config" do
|
@@ -113,7 +109,7 @@ describe Swagger::Docs::Generator do
|
|
113
109
|
generate(config)
|
114
110
|
end
|
115
111
|
it "cleans json files in directory when set" do
|
116
|
-
file_to_delete =
|
112
|
+
file_to_delete = Pathname.new(File.join(config['1.0'][:api_file_path], 'delete_me.json'))
|
117
113
|
File.open(file_to_delete, 'w') {|f| f.write("{}") }
|
118
114
|
expect(file_to_delete).to exist
|
119
115
|
config[DEFAULT_VER][:clean_directory] = true
|
@@ -121,17 +117,17 @@ describe Swagger::Docs::Generator do
|
|
121
117
|
expect(file_to_delete).to_not exist
|
122
118
|
end
|
123
119
|
it "keeps non json files in directory when cleaning" do
|
124
|
-
file_to_keep =
|
120
|
+
file_to_keep = Pathname.new(File.join(config['1.0'][:api_file_path], 'keep_me'))
|
125
121
|
File.open(file_to_keep, 'w') {|f| f.write("{}") }
|
126
122
|
config[DEFAULT_VER][:clean_directory] = true
|
127
123
|
generate(config)
|
128
124
|
expect(file_to_keep).to exist
|
129
125
|
end
|
130
126
|
it "writes the resources file" do
|
131
|
-
|
127
|
+
expect(file_resources).to exist
|
132
128
|
end
|
133
129
|
it "writes the resource file" do
|
134
|
-
|
130
|
+
expect(file_resource).to exist
|
135
131
|
end
|
136
132
|
it "returns results hash" do
|
137
133
|
results = generate(config)
|
@@ -141,11 +137,11 @@ describe Swagger::Docs::Generator do
|
|
141
137
|
it "writes pretty json files when set" do
|
142
138
|
config[DEFAULT_VER][:formatting] = :pretty
|
143
139
|
generate(config)
|
144
|
-
resources = File.read
|
140
|
+
resources = File.read file_resources
|
145
141
|
expect(resources.scan(/\n/).length).to be > 1
|
146
142
|
end
|
147
143
|
context "resources files" do
|
148
|
-
let(:resources) {
|
144
|
+
let(:resources) { file_resources.read }
|
149
145
|
let(:response) { JSON.parse(resources) }
|
150
146
|
it "writes version correctly" do
|
151
147
|
expect(response["apiVersion"]).to eq DEFAULT_VER
|
@@ -167,11 +163,9 @@ describe Swagger::Docs::Generator do
|
|
167
163
|
end
|
168
164
|
end
|
169
165
|
context "resource file" do
|
170
|
-
let(:resource) {
|
166
|
+
let(:resource) { file_resource.read }
|
171
167
|
let(:response) { JSON.parse(resource) }
|
172
|
-
let(:
|
173
|
-
let(:params) { operations.first["parameters"] }
|
174
|
-
let(:response_msgs) { operations.first["responseMessages"] }
|
168
|
+
let(:apis) { response["apis"] }
|
175
169
|
# {"apiVersion":"1.0","swaggerVersion":"1.2","basePath":"/api/v1","resourcePath":"/sample"
|
176
170
|
it "writes version correctly" do
|
177
171
|
expect(response["apiVersion"]).to eq DEFAULT_VER
|
@@ -186,75 +180,124 @@ describe Swagger::Docs::Generator do
|
|
186
180
|
expect(response["resourcePath"]).to eq "sample"
|
187
181
|
end
|
188
182
|
it "writes out expected api count" do
|
189
|
-
expect(response["apis"].count).to eq
|
183
|
+
expect(response["apis"].count).to eq 7
|
190
184
|
end
|
191
|
-
context "
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
config[DEFAULT_VER][:api_extension_type] = :json
|
200
|
-
generate(config)
|
201
|
-
expect(api["path"]).to eq "sample.json"
|
202
|
-
end
|
203
|
-
it "writes summary correctly" do
|
204
|
-
expect(operations.first["summary"]).to eq "Fetches all User items"
|
205
|
-
end
|
206
|
-
it "writes method correctly" do
|
207
|
-
expect(operations.first["method"]).to eq "get"
|
208
|
-
end
|
209
|
-
it "writes nickname correctly" do
|
210
|
-
expect(operations.first["nickname"]).to eq "Api::V1::Sample#index"
|
211
|
-
end
|
212
|
-
#"parameters"=>[
|
213
|
-
# {"paramType"=>"query", "name"=>"page", "type"=>"integer", "description"=>"Page number", "required"=>false},
|
214
|
-
# {"paramType"=>"path", "name"=>"nested_id", "type"=>"integer", "description"=>"Team Id", "required"=>false}], "responseMessages"=>[{"code"=>401, "message"=>"Unauthorized"}, {"code"=>406, "message"=>"The request you made is not acceptable"}, {"code"=>416, "message"=>"Requested Range Not Satisfiable"}], "method"=>"get", "nickname"=>"Api::V1::Sample#index"}
|
215
|
-
#]
|
216
|
-
context "parameters" do
|
217
|
-
it "has correct count" do
|
218
|
-
expect(params.count).to eq 1
|
185
|
+
context "apis" do
|
186
|
+
context "index" do
|
187
|
+
let(:api) { get_api_operation(apis, "sample", :get) }
|
188
|
+
let(:operations) { get_api_operations(apis, "sample") }
|
189
|
+
#"apis":[{"path":" /sample","operations":[{"summary":"Fetches all User items"
|
190
|
+
#,"method":"get","nickname":"Api::V1::Sample#index"}]
|
191
|
+
it "writes path correctly when api extension type is not set" do
|
192
|
+
expect(apis.first["path"]).to eq "sample"
|
219
193
|
end
|
220
|
-
it "writes
|
221
|
-
|
194
|
+
it "writes path correctly when api extension type is set" do
|
195
|
+
config[DEFAULT_VER][:api_extension_type] = :json
|
196
|
+
generate(config)
|
197
|
+
expect(apis.first["path"]).to eq "sample.json"
|
222
198
|
end
|
223
|
-
it "writes
|
224
|
-
expect(
|
199
|
+
it "writes summary correctly" do
|
200
|
+
expect(operations.first["summary"]).to eq "Fetches all User items"
|
225
201
|
end
|
226
|
-
it "writes
|
227
|
-
expect(
|
202
|
+
it "writes method correctly" do
|
203
|
+
expect(operations.first["method"]).to eq "get"
|
228
204
|
end
|
229
|
-
it "writes
|
230
|
-
expect(
|
205
|
+
it "writes nickname correctly" do
|
206
|
+
expect(operations.first["nickname"]).to eq "Api::V1::Sample#index"
|
231
207
|
end
|
232
|
-
|
233
|
-
|
208
|
+
#"parameters"=>[
|
209
|
+
# {"paramType"=>"query", "name"=>"page", "type"=>"integer", "description"=>"Page number", "required"=>false},
|
210
|
+
# {"paramType"=>"path", "name"=>"nested_id", "type"=>"integer", "description"=>"Team Id", "required"=>false}], "responseMessages"=>[{"code"=>401, "message"=>"Unauthorized"}, {"code"=>406, "message"=>"The request you made is not acceptable"}, {"code"=>416, "message"=>"Requested Range Not Satisfiable"}], "method"=>"get", "nickname"=>"Api::V1::Sample#index"}
|
211
|
+
#]
|
212
|
+
context "parameters" do
|
213
|
+
let(:params) { operations.first["parameters"] }
|
214
|
+
it "has correct count" do
|
215
|
+
expect(params.count).to eq 1
|
216
|
+
end
|
217
|
+
it "writes paramType correctly" do
|
218
|
+
expect(params.first["paramType"]).to eq "query"
|
219
|
+
end
|
220
|
+
it "writes name correctly" do
|
221
|
+
expect(params.first["name"]).to eq "page"
|
222
|
+
end
|
223
|
+
it "writes type correctly" do
|
224
|
+
expect(params.first["type"]).to eq "integer"
|
225
|
+
end
|
226
|
+
it "writes description correctly" do
|
227
|
+
expect(params.first["description"]).to eq "Page number"
|
228
|
+
end
|
229
|
+
it "writes required correctly" do
|
230
|
+
expect(params.first["required"]).to be_false
|
231
|
+
end
|
234
232
|
end
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
233
|
+
#"responseMessages":[{"code":401,"message":"Unauthorized"},{"code":406,"message":"Not Acceptable"},{"code":416,"message":"Requested Range Not Satisfiable"}]
|
234
|
+
context "response messages" do
|
235
|
+
let(:response_msgs) { operations.first["responseMessages"] }
|
236
|
+
it "has correct count" do
|
237
|
+
expect(response_msgs.count).to eq 3
|
238
|
+
end
|
239
|
+
it "writes code correctly" do
|
240
|
+
expect(response_msgs.first["code"]).to eq 401
|
241
|
+
end
|
242
|
+
it "writes message correctly" do
|
243
|
+
expect(response_msgs.first["message"]).to eq "Unauthorized"
|
244
|
+
end
|
245
|
+
it "writes specified message correctly" do
|
246
|
+
expect(response_msgs[1]["message"]).to eq "The request you made is not acceptable"
|
247
|
+
end
|
240
248
|
end
|
241
|
-
|
242
|
-
|
249
|
+
end
|
250
|
+
context "show" do
|
251
|
+
let(:api) { get_api_operation(apis, "nested/{nested_id}/sample", :get) }
|
252
|
+
let(:operations) { get_api_operations(apis, "nested/{nested_id}/sample") }
|
253
|
+
context "parameters" do
|
254
|
+
it "has correct count" do
|
255
|
+
expect(api["parameters"].count).to eq 2
|
256
|
+
end
|
243
257
|
end
|
244
|
-
|
245
|
-
|
258
|
+
end
|
259
|
+
context "create" do
|
260
|
+
let(:api) { get_api_operation(apis, "sample", :post) }
|
261
|
+
it "writes list parameter values correctly" do
|
262
|
+
expected_param = {"valueType"=>"LIST", "values"=>["admin", "superadmin", "user"]}
|
263
|
+
expect(get_api_parameter(api, "role")["allowableValues"]).to eq expected_param
|
246
264
|
end
|
247
|
-
|
248
|
-
|
265
|
+
end
|
266
|
+
context "update" do
|
267
|
+
let(:api) { get_api_operation(apis, "sample/{id}", :put) }
|
268
|
+
it "writes model param correctly" do
|
269
|
+
expected_param = {
|
270
|
+
"paramType" => "form",
|
271
|
+
"name" => "tag",
|
272
|
+
"type" => "Tag",
|
273
|
+
"description" => "Tag object",
|
274
|
+
"required" => true,
|
275
|
+
}
|
276
|
+
expect(get_api_parameter(api, "tag")).to eq expected_param
|
249
277
|
end
|
250
278
|
end
|
251
279
|
end
|
252
|
-
context "
|
253
|
-
let(:
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
280
|
+
context "models" do
|
281
|
+
let(:models) { response["models"] }
|
282
|
+
# Based on https://github.com/wordnik/swagger-core/wiki/Datatypes
|
283
|
+
it "writes model correctly" do
|
284
|
+
expected_model = {
|
285
|
+
"id" => "Tag",
|
286
|
+
"required" => ["id"],
|
287
|
+
"description" => "A Tag object.",
|
288
|
+
"properties" => {
|
289
|
+
"name" => {
|
290
|
+
"type" => "string",
|
291
|
+
"description" => "Name",
|
292
|
+
"foo" => "test",
|
293
|
+
},
|
294
|
+
"id" => {
|
295
|
+
"type" => "integer",
|
296
|
+
"description" => "User Id",
|
297
|
+
}
|
298
|
+
}
|
299
|
+
}
|
300
|
+
expect(models['Tag']).to eq expected_model
|
258
301
|
end
|
259
302
|
end
|
260
303
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,14 +6,39 @@ require 'pathname'
|
|
6
6
|
|
7
7
|
DEFAULT_VER = Swagger::Docs::Generator::DEFAULT_VER
|
8
8
|
|
9
|
-
TMP_DIR = Pathname.new "/tmp/swagger-docs/"
|
10
|
-
TMP_API_DIR = TMP_DIR+"api/v1"
|
11
|
-
FILE_RESOURCES = TMP_API_DIR+"api-docs.json"
|
12
|
-
FILE_RESOURCE = TMP_API_DIR+"sample.json"
|
13
|
-
|
14
9
|
RSpec.configure do |config|
|
15
10
|
config.expect_with :rspec do |c|
|
16
11
|
c.syntax = :expect
|
17
12
|
end
|
18
13
|
config.color_enabled = true
|
19
14
|
end
|
15
|
+
|
16
|
+
def generate(config)
|
17
|
+
Swagger::Docs::Generator::write_docs(config)
|
18
|
+
end
|
19
|
+
|
20
|
+
def stub_route(verb, action, controller, spec)
|
21
|
+
double("route", :verb => double("verb", :source => verb),
|
22
|
+
:defaults => {:action => action, :controller => controller},
|
23
|
+
:path => double("path", :spec => spec)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_api_paths(apis, path)
|
28
|
+
apis.select{|api| api["path"] == path}
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_api_operations(apis, path)
|
32
|
+
apis = get_api_paths(apis, path)
|
33
|
+
apis.collect{|api| api["operations"]}.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_api_operation(apis, path, method)
|
37
|
+
operations = get_api_operations(apis, path)
|
38
|
+
operations.each{|operation| return operation if operation["method"] == method.to_s}
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_api_parameter(api, name)
|
42
|
+
api["parameters"].each{|param| return param if param["name"] == name}
|
43
|
+
end
|
44
|
+
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swagger-docs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rich Hollis
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
RYcsqDfanYBx7QcftOnbeQq7/Ep7Zx+W9+Ph3TiJLMLdAr7bLkgN1SjvrjTL5mQR
|
31
31
|
FuQtYvE4LKiUQpG7vLTRB78dQBlSj9fnv2OM9w==
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date: 2014-02
|
33
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: bundler
|
metadata.gz.sig
CHANGED
@@ -1,3 +1 @@
|
|
1
|
-
D
|
2
|
-
6`�����ѽ��m����p�����������l��+�XK|`1�ds�B�{ɫ1'�.m��i��f�7�qY��
|
3
|
-
��tpS��
|
1
|
+
��Í��%��eb�D�',�gk��yf�8_*�@��v@H�4ȴ �)s�ҥ�?Ȏ�aQ��UO�'��|�|*���Z�p���/ݾ7�gL���L*����u��w�LƗ��F\�8���?��_�h��6���R�1Y�?m��dp��b�)>ܝكZa��,�p;pw��e@W��p��0�Ӵ�[ʦo�����h�MK��}�G�2��LN���*��Jz)�9-�w��4�e+�3ϝ�>��/�?xc�Ѧ�A}�
|