doctor-swagger 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Guardfile +24 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +10 -0
- data/doctor-swagger.gemspec +30 -0
- data/lib/doctor-swagger.rb +1 -0
- data/lib/doctor_swagger.rb +78 -0
- data/lib/doctor_swagger/endpoint.rb +32 -0
- data/lib/doctor_swagger/error_response.rb +15 -0
- data/lib/doctor_swagger/errors.rb +15 -0
- data/lib/doctor_swagger/operation.rb +100 -0
- data/lib/doctor_swagger/parameter.rb +65 -0
- data/lib/doctor_swagger/path_parameter.rb +7 -0
- data/lib/doctor_swagger/post_body.rb +19 -0
- data/lib/doctor_swagger/post_parameter.rb +7 -0
- data/lib/doctor_swagger/query_parameter.rb +7 -0
- data/lib/doctor_swagger/root_swagger_doc.rb +16 -0
- data/lib/doctor_swagger/swagger_doc.rb +37 -0
- data/lib/doctor_swagger/version.rb +3 -0
- data/spec/doctor_swagger_spec.rb +297 -0
- data/spec/spec_helper.rb +6 -0
- metadata +156 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara request specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
24
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Donald Plummer
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Doctor::Swagger
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'doctor-swagger'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install doctor-swagger
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
|
3
|
+
puts File.expand_path(File.join(File.basename(__FILE__), 'lib'))
|
4
|
+
require 'doctor_swagger/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.authors = ["Donald Plummer", "Michael Xavier"]
|
8
|
+
gem.email = ["developers@crystalcommerce.com"]
|
9
|
+
gem.description = %q{DSL for generating swagger resource documentation}
|
10
|
+
gem.summary = <<-EOS
|
11
|
+
Provides a mixin which gives a high-level DSL for describing a swagger
|
12
|
+
resource. Use this to generate a documentation endpoint to describe an API that
|
13
|
+
you wish to document with swagger.
|
14
|
+
EOS
|
15
|
+
gem.homepage = ""
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($\)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.name = "doctor-swagger"
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
gem.version = DoctorSwagger::VERSION
|
23
|
+
|
24
|
+
gem.add_dependency("rdiscount", "~>1.6.8")
|
25
|
+
|
26
|
+
gem.add_development_dependency("rake", "~>0.9.2")
|
27
|
+
gem.add_development_dependency("rspec", "~>2.10.0")
|
28
|
+
gem.add_development_dependency("guard", "~>1.2.1")
|
29
|
+
gem.add_development_dependency("guard-rspec", "~>1.1.0")
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "doctor_swagger"
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'doctor_swagger/endpoint'
|
2
|
+
require 'doctor_swagger/swagger_doc'
|
3
|
+
require 'doctor_swagger/error_response'
|
4
|
+
require 'doctor_swagger/errors'
|
5
|
+
require 'doctor_swagger/operation'
|
6
|
+
require 'doctor_swagger/parameter'
|
7
|
+
require 'doctor_swagger/query_parameter'
|
8
|
+
require 'doctor_swagger/post_parameter'
|
9
|
+
require 'doctor_swagger/path_parameter'
|
10
|
+
require 'doctor_swagger/post_body'
|
11
|
+
require 'doctor_swagger/root_swagger_doc'
|
12
|
+
|
13
|
+
module DoctorSwagger
|
14
|
+
#global settings, override with DSL
|
15
|
+
def self.swagger_version
|
16
|
+
@swagger_version ||= '1.0'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.api_version
|
20
|
+
@api_version ||= lambda { raise 'Set your API version with DoctorSwagger.api_version= or at the resource level'}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.base_path
|
24
|
+
@base_path ||= lambda { raise 'Set your base URL with DoctorSwagger.base_path= or at the resource level'}
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.swagger_version=(version)
|
28
|
+
@swagger_version = version
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.api_version=(version)
|
32
|
+
@api_version = version
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.base_path=(url)
|
36
|
+
@base_path = url
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
def swagger_version(version)
|
41
|
+
@swagger_version = version
|
42
|
+
end
|
43
|
+
|
44
|
+
def api_version(version)
|
45
|
+
@api_version = version
|
46
|
+
end
|
47
|
+
|
48
|
+
def base_path(url)
|
49
|
+
@base_path = url
|
50
|
+
end
|
51
|
+
|
52
|
+
def swagger_doc
|
53
|
+
@swagger_doc
|
54
|
+
end
|
55
|
+
|
56
|
+
def swagger_resource(resource_path, &block)
|
57
|
+
@swagger_doc = SwaggerDoc.new(resource_path,
|
58
|
+
:swagger_version => @swagger_version,
|
59
|
+
:api_version => @api_version,
|
60
|
+
:base_path => @base_path,
|
61
|
+
&block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def swagger_root_resource(resource_path, &block)
|
65
|
+
@swagger_doc = RootSwaggerDoc.new(resource_path,
|
66
|
+
:swagger_version => @swagger_version,
|
67
|
+
:api_version => @api_version,
|
68
|
+
:base_path => @base_path,
|
69
|
+
&block)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.included(receiver)
|
74
|
+
receiver.extend(ClassMethods)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
require "doctor_swagger/version"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DoctorSwagger
|
2
|
+
class Endpoint
|
3
|
+
def initialize(path, &block)
|
4
|
+
@path = path
|
5
|
+
@operations = []
|
6
|
+
instance_eval(&block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def operations_as_json
|
10
|
+
if @operations && !@operations.empty?
|
11
|
+
{'operations' => @operations.map(&:as_json)}
|
12
|
+
else
|
13
|
+
{}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_json(*)
|
18
|
+
{
|
19
|
+
'path' => @path,
|
20
|
+
'description' => @description,
|
21
|
+
}.merge(operations_as_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def description(desc)
|
25
|
+
@description = desc
|
26
|
+
end
|
27
|
+
|
28
|
+
def operation(nickname, &block)
|
29
|
+
@operations << Operation.new(nickname, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DoctorSwagger
|
2
|
+
module Errors
|
3
|
+
def self.standard_errors
|
4
|
+
[resource_not_found, access_denied]
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.resource_not_found
|
8
|
+
ErrorResponse.new(404, 'resource_not_found')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.access_denied
|
12
|
+
ErrorResponse.new(401, 'access_denied')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rdiscount'
|
2
|
+
|
3
|
+
module DoctorSwagger
|
4
|
+
class Operation
|
5
|
+
def initialize(nickname, &block)
|
6
|
+
@nickname = nickname
|
7
|
+
@summary = ''
|
8
|
+
@parameters = []
|
9
|
+
@error_responses = []
|
10
|
+
@embeds = []
|
11
|
+
@scopes = []
|
12
|
+
@type = ""
|
13
|
+
@internal_type = ""
|
14
|
+
instance_eval(&block)
|
15
|
+
add_embedded_parameter unless @embeds.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def query_parameter(param, &block)
|
19
|
+
@parameters << QueryParameter.new(param, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def path_parameter(param, &block)
|
23
|
+
@parameters << PathParameter.new(param, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post_parameter(param, &block)
|
27
|
+
@parameters << PostParameter.new(param, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def post_body(&block)
|
31
|
+
@parameters << PostBody.new(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def method(meth)
|
35
|
+
@method = meth
|
36
|
+
end
|
37
|
+
|
38
|
+
def notes(notes)
|
39
|
+
@notes = process_markdown(notes)
|
40
|
+
end
|
41
|
+
|
42
|
+
def summary(summary)
|
43
|
+
@summary = summary
|
44
|
+
end
|
45
|
+
|
46
|
+
def standard_errors
|
47
|
+
@error_responses |= Errors.standard_errors
|
48
|
+
end
|
49
|
+
|
50
|
+
def error(http_status, error)
|
51
|
+
@error_responses << ErrorResponse.new(http_status, error)
|
52
|
+
end
|
53
|
+
|
54
|
+
def embeds(*embeds)
|
55
|
+
@embeds |= embeds
|
56
|
+
end
|
57
|
+
|
58
|
+
def scopes(*scopes)
|
59
|
+
@scopes |= scopes
|
60
|
+
end
|
61
|
+
|
62
|
+
def type(type)
|
63
|
+
@type = type
|
64
|
+
end
|
65
|
+
|
66
|
+
def internal_type(internal_type)
|
67
|
+
@internal_type = internal_type
|
68
|
+
end
|
69
|
+
|
70
|
+
def as_json(*)
|
71
|
+
|
72
|
+
{
|
73
|
+
'parameters' => @parameters.map(&:as_json),
|
74
|
+
'httpMethod' => @method.to_s.upcase,
|
75
|
+
'notes' => @notes,
|
76
|
+
'embeds' => @embeds.map(&:to_s),
|
77
|
+
'scopes' => @scopes.map(&:to_s),
|
78
|
+
'errorResponses' => @error_responses.map(&:as_json),
|
79
|
+
'summary' => @summary,
|
80
|
+
'nickname' => @nickname.to_s,
|
81
|
+
'responseClass' => @type,
|
82
|
+
'responseTypeInternal' => @internal_type
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def add_embedded_parameter
|
88
|
+
embeds = @embeds
|
89
|
+
query_parameter(:embedded) do
|
90
|
+
description "Optional records to embed, comma-separated"
|
91
|
+
allow_multiple! if embeds.length > 1
|
92
|
+
allowable_values(*embeds)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_markdown(text)
|
97
|
+
RDiscount.new(text).to_html
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module DoctorSwagger
|
2
|
+
class Parameter
|
3
|
+
ALLOWED_TYPES = [:string, :integer, :long, :double, :boolean]
|
4
|
+
class InvalidType < StandardError
|
5
|
+
def initialize(bad_type)
|
6
|
+
@message = "The type of '#{bad_type}' is not valid. Choose from #{ALLOWED_TYPES.inspect}"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(name, &block)
|
11
|
+
@name = name
|
12
|
+
@description = ""
|
13
|
+
@required = false
|
14
|
+
@allow_multiple = false
|
15
|
+
@allowable_values = []
|
16
|
+
@data_type = :string
|
17
|
+
instance_eval(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def description(description)
|
21
|
+
@description = description
|
22
|
+
end
|
23
|
+
|
24
|
+
def required!
|
25
|
+
@required = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def allow_multiple!
|
29
|
+
@allow_multiple = true
|
30
|
+
end
|
31
|
+
|
32
|
+
def allowable_values(*values)
|
33
|
+
@allowable_values |= values
|
34
|
+
end
|
35
|
+
|
36
|
+
def type(type)
|
37
|
+
raise InvalidType.new(type) unless ALLOWED_TYPES.include?(type)
|
38
|
+
@data_type = type
|
39
|
+
end
|
40
|
+
|
41
|
+
def allowable_values_as_json
|
42
|
+
if @allowable_values && !@allowable_values.empty?
|
43
|
+
{
|
44
|
+
'allowableValues' => {
|
45
|
+
'valueType' => 'LIST',
|
46
|
+
'values' => @allowable_values.map(&:to_s)
|
47
|
+
}
|
48
|
+
}
|
49
|
+
else
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def as_json(*)
|
55
|
+
{
|
56
|
+
'name' => @name.to_s,
|
57
|
+
'description' => @description,
|
58
|
+
'dataType' => @data_type.to_s,
|
59
|
+
'required' => @required,
|
60
|
+
'allowMultiple' => @allow_multiple,
|
61
|
+
'paramType' => param_type
|
62
|
+
}.merge(allowable_values_as_json)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DoctorSwagger
|
2
|
+
class PostBody < PostParameter
|
3
|
+
def initialize(&block)
|
4
|
+
super(:body, &block)
|
5
|
+
end
|
6
|
+
|
7
|
+
def example(example)
|
8
|
+
@example = example
|
9
|
+
end
|
10
|
+
|
11
|
+
def as_json(*)
|
12
|
+
if @example && !@example.empty?
|
13
|
+
super.merge('example' => @example)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#TODO: specme
|
2
|
+
module DoctorSwagger
|
3
|
+
class RootSwaggerDoc < SwaggerDoc
|
4
|
+
def initialize(base_path_extension, options = {}, &block)
|
5
|
+
options[:swagger_version] ||= DoctorSwagger.swagger_version
|
6
|
+
options[:api_version] ||= DoctorSwagger.api_version
|
7
|
+
options[:base_path] ||= DoctorSwagger.base_path
|
8
|
+
@swagger_version = options[:swagger_version]
|
9
|
+
@api_version = options[:api_version]
|
10
|
+
@base_path = try_call(options[:base_path])
|
11
|
+
@base_path += base_path_extension
|
12
|
+
@endpoints = []
|
13
|
+
instance_eval(&block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module DoctorSwagger
|
2
|
+
class SwaggerDoc
|
3
|
+
|
4
|
+
def initialize(resource_path, options = {}, &block)
|
5
|
+
@resource_path = resource_path
|
6
|
+
options[:swagger_version] ||= DoctorSwagger.swagger_version
|
7
|
+
options[:api_version] ||= DoctorSwagger.api_version
|
8
|
+
options[:base_path] ||= DoctorSwagger.base_path
|
9
|
+
@swagger_version = options[:swagger_version]
|
10
|
+
@api_version = options[:api_version]
|
11
|
+
@base_path = options[:base_path]
|
12
|
+
@endpoints = []
|
13
|
+
instance_eval(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def endpoint(path, &block)
|
17
|
+
@endpoints << Endpoint.new(path, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
#TODO: add DSL for
|
21
|
+
def as_json(*)
|
22
|
+
{
|
23
|
+
'apiVersion' => try_call(@api_version),
|
24
|
+
'swaggerVersion' => try_call(@swagger_version),
|
25
|
+
'basePath' => try_call(@base_path),
|
26
|
+
'resourcePath' => @resource_path,
|
27
|
+
'apis' => @endpoints.map(&:as_json)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def try_call(value)
|
34
|
+
value.respond_to?(:call) ? value.call : value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'doctor-swagger'
|
3
|
+
|
4
|
+
describe DoctorSwagger do
|
5
|
+
module DoctorSwaggerTest
|
6
|
+
include DoctorSwagger
|
7
|
+
|
8
|
+
swagger_version 'some crazy version'
|
9
|
+
api_version '3.0'
|
10
|
+
base_path 'https://example.com/api'
|
11
|
+
|
12
|
+
swagger_resource '/products' do
|
13
|
+
endpoint '/products' do
|
14
|
+
description 'Products'
|
15
|
+
|
16
|
+
operation :index do
|
17
|
+
query_parameter :category_id do
|
18
|
+
description 'The category id of the products you want'
|
19
|
+
required!
|
20
|
+
type :integer
|
21
|
+
end
|
22
|
+
|
23
|
+
method :get
|
24
|
+
notes 'Returns lots of products'
|
25
|
+
|
26
|
+
type '[product]'
|
27
|
+
internal_type '[Product]'
|
28
|
+
|
29
|
+
standard_errors
|
30
|
+
error 418, "im_a_teapot"
|
31
|
+
|
32
|
+
embeds :category, :variants
|
33
|
+
scopes 'read-inventory', 'other-scope'
|
34
|
+
summary 'Find products by category id'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
endpoint '/products/{product_id}' do
|
39
|
+
description 'Show product'
|
40
|
+
|
41
|
+
operation :show do
|
42
|
+
path_parameter :product_id do
|
43
|
+
description 'The product id of the product you want'
|
44
|
+
required!
|
45
|
+
type :integer
|
46
|
+
end
|
47
|
+
|
48
|
+
method :get
|
49
|
+
notes 'Returns a product'
|
50
|
+
|
51
|
+
type 'product'
|
52
|
+
internal_type 'Product'
|
53
|
+
|
54
|
+
standard_errors
|
55
|
+
embeds :category, :variants
|
56
|
+
scopes 'read-inventory', 'other-scope'
|
57
|
+
summary 'Find product by product id'
|
58
|
+
end
|
59
|
+
|
60
|
+
operation :update do
|
61
|
+
path_parameter :product_id do
|
62
|
+
description 'The product id of the product you want'
|
63
|
+
required!
|
64
|
+
type :integer
|
65
|
+
end
|
66
|
+
|
67
|
+
post_body do
|
68
|
+
description 'The JSON representation of the product'
|
69
|
+
required!
|
70
|
+
|
71
|
+
example 'product' => {
|
72
|
+
'foo' => 'bar',
|
73
|
+
'wat' => nil
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
method :put
|
78
|
+
notes <<-EOS
|
79
|
+
# Updates a *product*
|
80
|
+
EOS
|
81
|
+
|
82
|
+
type 'product'
|
83
|
+
internal_type 'Product'
|
84
|
+
|
85
|
+
standard_errors
|
86
|
+
scopes 'read-inventory', 'other-scope'
|
87
|
+
summary 'Update product by product id'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
subject { DoctorSwaggerTest.swagger_doc }
|
94
|
+
|
95
|
+
before(:each) do
|
96
|
+
@actual = DoctorSwaggerTest.swagger_doc
|
97
|
+
end
|
98
|
+
|
99
|
+
its(:as_json) do
|
100
|
+
should == {
|
101
|
+
'apiVersion' => '3.0',
|
102
|
+
'swaggerVersion' => 'some crazy version',
|
103
|
+
'basePath' => "https://example.com/api",
|
104
|
+
'resourcePath' => '/products',
|
105
|
+
'apis' => [
|
106
|
+
{
|
107
|
+
'path' => '/products',
|
108
|
+
'description' => 'Products',
|
109
|
+
'operations' => [
|
110
|
+
{
|
111
|
+
'parameters' => [
|
112
|
+
{
|
113
|
+
'name' => 'category_id',
|
114
|
+
'description' => 'The category id of the products you want',
|
115
|
+
'dataType' => 'integer',
|
116
|
+
'required' => true,
|
117
|
+
'allowMultiple' => false,
|
118
|
+
'paramType' => 'query'
|
119
|
+
},
|
120
|
+
{
|
121
|
+
'name' => 'embedded',
|
122
|
+
'description' => 'Optional records to embed, comma-separated',
|
123
|
+
'dataType' => 'string',
|
124
|
+
'required' => false,
|
125
|
+
'allowMultiple' => true,
|
126
|
+
'paramType' => 'query',
|
127
|
+
'allowableValues' => {
|
128
|
+
'values' => %w[category variants],
|
129
|
+
'valueType' => 'LIST'
|
130
|
+
}
|
131
|
+
}
|
132
|
+
],
|
133
|
+
'httpMethod' => 'GET',
|
134
|
+
'notes' => "<p>Returns lots of products</p>\n",
|
135
|
+
'embeds' => %w[category variants],
|
136
|
+
'scopes' => %w[read-inventory other-scope],
|
137
|
+
'responseTypeInternal' => '[Product]',
|
138
|
+
'responseClass' => '[product]',
|
139
|
+
'errorResponses' => [
|
140
|
+
{
|
141
|
+
'error' => 'resource_not_found',
|
142
|
+
'http_status' => 404
|
143
|
+
},
|
144
|
+
{
|
145
|
+
'error' => 'access_denied',
|
146
|
+
'http_status' => 401
|
147
|
+
},
|
148
|
+
{
|
149
|
+
'error' => 'im_a_teapot',
|
150
|
+
'http_status' => 418
|
151
|
+
}
|
152
|
+
],
|
153
|
+
'summary' => 'Find products by category id',
|
154
|
+
'nickname' => 'index'
|
155
|
+
|
156
|
+
}
|
157
|
+
]
|
158
|
+
},
|
159
|
+
{
|
160
|
+
'path' => '/products/{product_id}',
|
161
|
+
'description' => 'Show product',
|
162
|
+
'operations' => [
|
163
|
+
{
|
164
|
+
'parameters' => [
|
165
|
+
{
|
166
|
+
'name' => 'product_id',
|
167
|
+
'description' => 'The product id of the product you want',
|
168
|
+
'dataType' => 'integer',
|
169
|
+
'required' => true,
|
170
|
+
'allowMultiple' => false,
|
171
|
+
'paramType' => 'path'
|
172
|
+
},
|
173
|
+
{
|
174
|
+
'name' => 'embedded',
|
175
|
+
'description' => 'Optional records to embed, comma-separated',
|
176
|
+
'dataType' => 'string',
|
177
|
+
'required' => false,
|
178
|
+
'allowMultiple' => true,
|
179
|
+
'paramType' => 'query',
|
180
|
+
'allowableValues' => {
|
181
|
+
'values' => %w[category variants],
|
182
|
+
'valueType' => 'LIST'
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
],
|
187
|
+
'httpMethod' => 'GET',
|
188
|
+
'notes' => "<p>Returns a product</p>\n",
|
189
|
+
'embeds' => %w[category variants],
|
190
|
+
'scopes' => %w[read-inventory other-scope],
|
191
|
+
'responseTypeInternal' => 'Product',
|
192
|
+
'responseClass' => 'product',
|
193
|
+
'errorResponses' => [
|
194
|
+
{
|
195
|
+
'error' => 'resource_not_found',
|
196
|
+
'http_status' => 404
|
197
|
+
},
|
198
|
+
{
|
199
|
+
'error' => 'access_denied',
|
200
|
+
'http_status' => 401
|
201
|
+
}
|
202
|
+
],
|
203
|
+
'summary' => 'Find product by product id',
|
204
|
+
'nickname' => 'show',
|
205
|
+
'scopes' => %w[read-inventory other-scope]
|
206
|
+
|
207
|
+
},
|
208
|
+
{
|
209
|
+
'parameters' => [
|
210
|
+
{
|
211
|
+
'name' => 'product_id',
|
212
|
+
'description' => 'The product id of the product you want',
|
213
|
+
'dataType' => 'integer',
|
214
|
+
'required' => true,
|
215
|
+
'allowMultiple' => false,
|
216
|
+
'paramType' => 'path'
|
217
|
+
},
|
218
|
+
{
|
219
|
+
'name' => 'body',
|
220
|
+
'description' => 'The JSON representation of the product',
|
221
|
+
'dataType' => 'string',
|
222
|
+
'required' => true,
|
223
|
+
'allowMultiple' => false,
|
224
|
+
'paramType' => 'post',
|
225
|
+
'example' => {
|
226
|
+
'product' => {
|
227
|
+
'foo' => 'bar',
|
228
|
+
'wat' => nil
|
229
|
+
}
|
230
|
+
}
|
231
|
+
},
|
232
|
+
],
|
233
|
+
'httpMethod' => 'PUT',
|
234
|
+
'notes' => "<h1>Updates a <em>product</em></h1>\n",
|
235
|
+
'embeds' => %w[],
|
236
|
+
'scopes' => %w[read-inventory other-scope],
|
237
|
+
'responseTypeInternal' => 'Product',
|
238
|
+
'responseClass' => 'product',
|
239
|
+
'errorResponses' => [
|
240
|
+
{
|
241
|
+
'error' => 'resource_not_found',
|
242
|
+
'http_status' => 404
|
243
|
+
},
|
244
|
+
{
|
245
|
+
'error' => 'access_denied',
|
246
|
+
'http_status' => 401
|
247
|
+
}
|
248
|
+
],
|
249
|
+
'summary' => 'Update product by product id',
|
250
|
+
'nickname' => 'update',
|
251
|
+
'scopes' => %w[read-inventory other-scope]
|
252
|
+
|
253
|
+
}
|
254
|
+
]
|
255
|
+
}
|
256
|
+
]
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
context "dynamic version/path config" do
|
261
|
+
class DynamicSwaggerResource
|
262
|
+
include DoctorSwagger
|
263
|
+
|
264
|
+
|
265
|
+
def self.prefix=(prefix)
|
266
|
+
@prefix = prefix
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.format(str)
|
270
|
+
"#{@prefix}#{str}"
|
271
|
+
end
|
272
|
+
|
273
|
+
swagger_version lambda { DynamicSwaggerResource.format('some crazy version') }
|
274
|
+
api_version lambda { DynamicSwaggerResource.format('3.0') }
|
275
|
+
base_path lambda { DynamicSwaggerResource.format('https://example.com/api') }
|
276
|
+
|
277
|
+
swagger_resource '/products' do
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
subject { DynamicSwaggerResource.swagger_doc }
|
282
|
+
|
283
|
+
before(:each) do
|
284
|
+
DynamicSwaggerResource.prefix = '!!!'
|
285
|
+
end
|
286
|
+
|
287
|
+
its(:as_json) do
|
288
|
+
should == {
|
289
|
+
'apiVersion' => '!!!3.0',
|
290
|
+
'swaggerVersion' => '!!!some crazy version',
|
291
|
+
'basePath' => "!!!https://example.com/api",
|
292
|
+
'resourcePath' => '/products',
|
293
|
+
'apis' => []
|
294
|
+
}
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: doctor-swagger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Donald Plummer
|
9
|
+
- Michael Xavier
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-09-27 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rdiscount
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.6.8
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 1.6.8
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rake
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.9.2
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.9.2
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.10.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.10.0
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: guard
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.2.1
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 1.2.1
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: guard-rspec
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ~>
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 1.1.0
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 1.1.0
|
95
|
+
description: DSL for generating swagger resource documentation
|
96
|
+
email:
|
97
|
+
- developers@crystalcommerce.com
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- .rspec
|
104
|
+
- .rvmrc
|
105
|
+
- Gemfile
|
106
|
+
- Guardfile
|
107
|
+
- LICENSE
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- doctor-swagger.gemspec
|
111
|
+
- lib/doctor-swagger.rb
|
112
|
+
- lib/doctor_swagger.rb
|
113
|
+
- lib/doctor_swagger/endpoint.rb
|
114
|
+
- lib/doctor_swagger/error_response.rb
|
115
|
+
- lib/doctor_swagger/errors.rb
|
116
|
+
- lib/doctor_swagger/operation.rb
|
117
|
+
- lib/doctor_swagger/parameter.rb
|
118
|
+
- lib/doctor_swagger/path_parameter.rb
|
119
|
+
- lib/doctor_swagger/post_body.rb
|
120
|
+
- lib/doctor_swagger/post_parameter.rb
|
121
|
+
- lib/doctor_swagger/query_parameter.rb
|
122
|
+
- lib/doctor_swagger/root_swagger_doc.rb
|
123
|
+
- lib/doctor_swagger/swagger_doc.rb
|
124
|
+
- lib/doctor_swagger/version.rb
|
125
|
+
- spec/doctor_swagger_spec.rb
|
126
|
+
- spec/spec_helper.rb
|
127
|
+
homepage: ''
|
128
|
+
licenses: []
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 1.8.24
|
148
|
+
signing_key:
|
149
|
+
specification_version: 3
|
150
|
+
summary: Provides a mixin which gives a high-level DSL for describing a swagger resource.
|
151
|
+
Use this to generate a documentation endpoint to describe an API that you wish to
|
152
|
+
document with swagger.
|
153
|
+
test_files:
|
154
|
+
- spec/doctor_swagger_spec.rb
|
155
|
+
- spec/spec_helper.rb
|
156
|
+
has_rdoc:
|