swagger-docs 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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}�
|