swagger-doc-rails 1.0.0

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.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Appraisals +7 -0
  4. data/CHANGELOG.md +120 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +448 -0
  8. data/Rakefile +10 -0
  9. data/certs/gem-public_cert.pem +21 -0
  10. data/lib/swagger/docs.rb +14 -0
  11. data/lib/swagger/docs/api_declaration_file.rb +125 -0
  12. data/lib/swagger/docs/api_declaration_file_metadata.rb +22 -0
  13. data/lib/swagger/docs/config.rb +63 -0
  14. data/lib/swagger/docs/dsl.rb +119 -0
  15. data/lib/swagger/docs/generator.rb +327 -0
  16. data/lib/swagger/docs/impotent_methods.rb +24 -0
  17. data/lib/swagger/docs/methods.rb +52 -0
  18. data/lib/swagger/docs/task.rb +9 -0
  19. data/lib/swagger/docs/version.rb +5 -0
  20. data/lib/tasks/swagger.rake +10 -0
  21. data/spec/fixtures/controllers/application_controller.rb +4 -0
  22. data/spec/fixtures/controllers/custom_resource_path_controller.rb +18 -0
  23. data/spec/fixtures/controllers/ignored_controller.rb +6 -0
  24. data/spec/fixtures/controllers/multiple_routes_controller.rb +13 -0
  25. data/spec/fixtures/controllers/nested_controller.rb +18 -0
  26. data/spec/fixtures/controllers/sample_controller.rb +81 -0
  27. data/spec/lib/swagger/docs/api_declaration_file_metadata_spec.rb +48 -0
  28. data/spec/lib/swagger/docs/api_declaration_file_spec.rb +203 -0
  29. data/spec/lib/swagger/docs/config_spec.rb +48 -0
  30. data/spec/lib/swagger/docs/dsl_spec.rb +17 -0
  31. data/spec/lib/swagger/docs/generator_spec.rb +451 -0
  32. data/spec/lib/swagger/docs/methods.rb +15 -0
  33. data/spec/spec_helper.rb +56 -0
  34. data/swagger-doc-rails.gemspec +31 -0
  35. metadata +175 -0
@@ -0,0 +1,24 @@
1
+ module Swagger
2
+ module Docs
3
+ module ImpotentMethods
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ private
11
+
12
+ def swagger_api(action, params = {}, &block)
13
+ end
14
+
15
+ def swagger_model(model_name, &block)
16
+ end
17
+
18
+ def swagger_controller(controller, description, params={})
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ require "active_support/core_ext/hash/deep_merge"
2
+ module Swagger
3
+ module Docs
4
+ module Methods
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def swagger_controller(controller, description, params = {})
11
+ swagger_config[:controller] = controller
12
+ swagger_config[:description] = description
13
+ swagger_config[:resource_path] = params[:resource_path]
14
+ end
15
+
16
+ def swagger_actions
17
+ swagger_dsl = {}
18
+ Array(@swagger_dsl).each do |action, params, controller, block|
19
+ dsl = SwaggerDSL.call(action, controller, &block)
20
+ swagger_dsl[action] ||= {}
21
+ swagger_dsl[action].deep_merge!(dsl) { |key, old, new| Array(old) + Array(new) }
22
+ swagger_dsl[action].deep_merge!(params) # merge in user api parameters
23
+ end
24
+ swagger_dsl
25
+ end
26
+
27
+ def swagger_models
28
+ swagger_model_dsls ||= {}
29
+ Array(@swagger_model_dsls).each do |model_name, controller, block|
30
+ model_dsl = SwaggerModelDSL.call(model_name, controller, &block)
31
+ swagger_model_dsls[model_name] = model_dsl
32
+ end
33
+ swagger_model_dsls
34
+ end
35
+
36
+ def swagger_config
37
+ @swagger_config ||= {}
38
+ end
39
+
40
+ def swagger_api(action, params = {}, &block)
41
+ @swagger_dsl ||= []
42
+ @swagger_dsl << [action, params, self, block]
43
+ end
44
+
45
+ def swagger_model(model_name, &block)
46
+ @swagger_model_dsls ||= []
47
+ @swagger_model_dsls << [model_name, self, block]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,9 @@
1
+ module Swagger
2
+ module Docs
3
+ class Task < Rails::Railtie
4
+ rake_tasks do
5
+ Dir[File.join(File.dirname(__FILE__),'../../tasks/*.rake')].each { |f| load f }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Swagger
2
+ module Docs
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ namespace :swagger do
2
+
3
+ desc "Generate Swagger documentation files"
4
+ task :docs => [:environment] do |t,args|
5
+ results = Swagger::Docs::Generator.write_docs(Swagger::Docs::Config.registered_apis)
6
+ results.each do |k,v|
7
+ puts "#{k}: #{v[:processed].count} processed / #{v[:skipped].count} skipped"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationController
2
+ cattr_accessor :context
3
+ self.context = "original"
4
+ end
@@ -0,0 +1,18 @@
1
+ module Api
2
+ module V1
3
+ class SuperclassController < ApplicationController
4
+ end
5
+ class CustomResourcePathController < SuperclassController
6
+ swagger_controller :custom_resource_path, "User Management", resource_path: "resource/testing"
7
+
8
+ swagger_api :index do
9
+ summary "Fetches all User items"
10
+ param :query, :page, :integer, :optional, "Page number"
11
+ param :path, :nested_id, :integer, :optional, "Team Id"
12
+ response :unauthorized
13
+ response :not_acceptable, "The request you made is not acceptable"
14
+ response :requested_range_not_satisfiable
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ module Api
2
+ module V1
3
+ class IgnoredController
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module Api
2
+ module V1
3
+ class MultipleRoutesController < ApplicationController
4
+ swagger_controller :multiple_routes, "Multiple Routes"
5
+
6
+ swagger_api :index do
7
+ summary "Creates a new User"
8
+ param :form, :first_name, :string, :required, "First name"
9
+ response :unauthorized
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Api
2
+ module V1
3
+ class SuperclassController < ApplicationController
4
+ end
5
+ class NestedController < SuperclassController
6
+ swagger_controller :nested, "User Management"
7
+
8
+ swagger_api :index do
9
+ summary "Fetches all User items"
10
+ param :query, :page, :integer, :optional, "Page number"
11
+ param :path, :nested_id, :integer, :optional, "Team Id"
12
+ response :unauthorized
13
+ response :not_acceptable, "The request you made is not acceptable"
14
+ response :requested_range_not_satisfiable
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,81 @@
1
+ module Api
2
+ module V1
3
+ class SuperclassController < ApplicationController
4
+ end
5
+ class SampleController < SuperclassController
6
+ swagger_controller :users, "User Management"
7
+
8
+ swagger_api :index do
9
+ summary "Fetches all User items"
10
+ param :query, :page, :integer, :optional, "Page number"
11
+ param :path, :nested_id, :integer, :optional, "Team Id"
12
+ response :ok, "Some text", :Tag
13
+ response :unauthorized
14
+ response :not_acceptable, "The request you made is not acceptable"
15
+ response :requested_range_not_satisfiable
16
+ end
17
+
18
+ swagger_api :show do
19
+ summary "Fetches a single User item"
20
+ param :path, :id, :integer, :optional, "User Id"
21
+ response :unauthorized
22
+ response :not_acceptable
23
+ response :not_found
24
+ end
25
+
26
+ swagger_api :create do
27
+ summary "Creates a new User"
28
+ consumes [ "application/json", "text/xml" ]
29
+ param :form, :first_name, :string, :required, "First name"
30
+ param :form, :last_name, :string, :required, "Last name"
31
+ param :form, :email, :string, :required, "Email address"
32
+ param_list :form, :role, :string, :required, "Role", [ "admin", "superadmin", "user" ]
33
+ param :body, :body, :json, :required, 'JSON formatted body'
34
+ items '{$ref" => "setup"}'
35
+ response :unauthorized
36
+ response :not_acceptable
37
+ end
38
+
39
+ swagger_api :update do
40
+ summary "Updates an existing User"
41
+ notes "Only the given fields are updated."
42
+ param :path, :id, :integer, :required, "User Id"
43
+ param :form, :first_name, :string, :optional, "First name"
44
+ param :form, :last_name, :string, :optional, "Last name"
45
+ param :form, :email, :string, :optional, "Email address"
46
+ param :form, :tag, :Tag, :required, "Tag object"
47
+ response :unauthorized
48
+ response :not_found
49
+ response :not_acceptable
50
+ end
51
+
52
+ swagger_api :destroy do
53
+ summary "Deletes an existing User item"
54
+ param :path, :id, :integer, :optional, "User Id"
55
+ response :unauthorized
56
+ response :not_found
57
+ end
58
+
59
+ # a method that intentionally has no parameters
60
+ swagger_api :new do
61
+ summary "Builds a new User item"
62
+ end
63
+
64
+ swagger_api :context_dependent do
65
+ summary "An action dependent on the context of the controller " +
66
+ "class. Right now it is: " + ApplicationController.context
67
+ response :ok
68
+ response :unauthorized
69
+ end
70
+
71
+ # Support for Swagger complex types:
72
+ # https://github.com/wordnik/swagger-core/wiki/Datatypes#wiki-complex-types
73
+ swagger_model :Tag do
74
+ description "A Tag object."
75
+ property :id, :integer, :required, "User Id"
76
+ property :name, :string, :optional, "Name", foo: "test"
77
+ property_list :type, :string, :optional, "Type", ["info", "warning", "error"]
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Swagger::Docs::ApiDeclarationFileMetadata do
4
+
5
+ describe "#initialize" do
6
+ it "sets the api_version property" do
7
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
8
+ expect(metadata.api_version).to eq("1.0")
9
+ end
10
+ it "sets the path property" do
11
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
12
+ expect(metadata.path).to eq("path")
13
+ end
14
+ it "sets the base_path property" do
15
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
16
+ expect(metadata.base_path).to eq("basePath")
17
+ end
18
+ it "sets the controller_base_path property" do
19
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
20
+ expect(metadata.controller_base_path).to eq("controllerBasePath")
21
+ end
22
+ it "defaults the swagger_version property to DEFAULT_SWAGGER_VERSION" do
23
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
24
+ expect(metadata.swagger_version).to eq(described_class::DEFAULT_SWAGGER_VERSION)
25
+ end
26
+ it "allows the swagger_version property to be_overriden" do
27
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath", swagger_version: "2.0")
28
+ expect(metadata.swagger_version).to eq("2.0")
29
+ end
30
+ it "defaults the camelize_model_properties property to true" do
31
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
32
+ expect(metadata.camelize_model_properties).to eq(true)
33
+ end
34
+ it "allows the camelize_model_properties property to be overidden" do
35
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath", camelize_model_properties: false)
36
+ expect(metadata.camelize_model_properties).to eq(false)
37
+ end
38
+ it "defaults the authorizations property to empty hash" do
39
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
40
+ expect(metadata.authorizations).to eq({})
41
+ end
42
+ it "allows the authorizations property to be overidden" do
43
+ authorizations = {foo: 'bar'}
44
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath", authorizations: authorizations)
45
+ expect(metadata.authorizations).to eq(authorizations)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,203 @@
1
+ require "spec_helper"
2
+
3
+ describe Swagger::Docs::ApiDeclarationFile do
4
+ let(:apis) do
5
+ [
6
+ {
7
+ :path=>"sample/{id}",
8
+ :operations=>[
9
+ {
10
+ :summary=>"Updates an existing User",
11
+ :parameters=>[
12
+ {:param_type=>:path, :name=>:id, :type=>:integer, :description=>"User Id", :required=>true},
13
+ {:param_type=>:form, :name=>:first_name, :type=>:string, :description=>"First name", :required=>false},
14
+ {:param_type=>:form, :name=>:last_name, :type=>:string, :description=>"Last name", :required=>false},
15
+ {:param_type=>:form, :name=>:email, :type=>:string, :description=>"Email address", :required=>false},
16
+ {:param_type=>:form, :name=>:tag, :type=>:Tag, :description=>"Tag object", :required=>true}
17
+ ],
18
+ :response_messages=>[
19
+ {:code=>401, :message=>"Unauthorized"},
20
+ {:code=>404, :message=>"Not Found"},
21
+ {:code=>406, :message=>"Not Acceptable"}
22
+ ],
23
+ :notes=>"Only the given fields are updated.",
24
+ :method=>:put,
25
+ :nickname=>"Api::V1::Sample#update",
26
+ :consumes=>["application/json", "text/xml"]
27
+ }
28
+ ]
29
+ }
30
+ ]
31
+ end
32
+ let(:models) do
33
+ {
34
+ :Tag=>
35
+ {
36
+ :id=>:Tag,
37
+ :required=>[:id],
38
+ :properties=>
39
+ {
40
+ :id=>{:type=>:integer, :description=>"User Id"},
41
+ :first_name=>{:type=>:string, :description=>"First Name"},
42
+ :last_name=>{:type=>:string, :description=>"Last Name"}
43
+ },
44
+ :description=>"A Tag object."
45
+ }
46
+ }
47
+ end
48
+ let(:metadata) do
49
+ Swagger::Docs::ApiDeclarationFileMetadata.new("1.0", "api/v1/sample", "http://api.no.where/", "")
50
+ end
51
+
52
+ describe "#generate_resource" do
53
+ it "generates the appropriate response" do
54
+ declaration = described_class.new(metadata, apis, models)
55
+
56
+ expected_response = {
57
+ "apiVersion"=> declaration.api_version,
58
+ "swaggerVersion"=> declaration.swagger_version,
59
+ "basePath"=> declaration.base_path,
60
+ "apis"=> declaration.apis,
61
+ "resourcePath"=> declaration.resource_path,
62
+ :models=> declaration.models,
63
+ "resourceFilePath" => declaration.resource_file_path,
64
+ "authorizations" => {}
65
+ }
66
+ expect(declaration.generate_resource).to eq(expected_response)
67
+ end
68
+ end
69
+ describe "#base_path" do
70
+ it "returns metadata.base_path" do
71
+ metadata = double("metadata", base_path: "/hello")
72
+ declaration = described_class.new(metadata, apis, models)
73
+ expect(declaration.base_path).to eq(metadata.base_path)
74
+ end
75
+ end
76
+ describe "#path" do
77
+ it "returns metadata.path" do
78
+ metadata = double("metadata", path: "/hello")
79
+ declaration = described_class.new(metadata, apis, models)
80
+ expect(declaration.path).to eq(metadata.path)
81
+ end
82
+ end
83
+ describe "#controller_base_path" do
84
+ it "returns metadata.controller_base_path" do
85
+ metadata = double("metadata", controller_base_path: "/hello")
86
+ declaration = described_class.new(metadata, apis, models)
87
+ expect(declaration.controller_base_path).to eq(metadata.controller_base_path)
88
+ end
89
+ end
90
+ describe "#resource_path" do
91
+ it "returns the debased controller path" do
92
+ metadata = double("metadata", overridden_resource_path: nil, controller_base_path: "/hello", path: "/hello/test-endpoint")
93
+ declaration = described_class.new(metadata, apis, models)
94
+ expect(declaration.resource_path).to eq("test_endpoint")
95
+ end
96
+ context "with an overridden_resource_path" do
97
+ it "returns the overriden resource path directly" do
98
+ metadata = double("metadata", overridden_resource_path: "testing-path", controller_base_path: "/hello", path: "/hello/test-endpoint")
99
+ declaration = described_class.new(metadata, apis, models)
100
+ expect(declaration.resource_path).to eq("testing-path")
101
+ end
102
+ end
103
+ end
104
+ describe "#swagger_version" do
105
+ it "returns metadata.swagger_version" do
106
+ metadata = double("metadata", swagger_version: "1.2")
107
+ declaration = described_class.new(metadata, apis, models)
108
+ expect(declaration.swagger_version).to eq(metadata.swagger_version)
109
+ end
110
+ end
111
+ describe "#api_version" do
112
+ it "returns metadata.api_version" do
113
+ metadata = double("metadata", api_version: "1.0")
114
+ declaration = described_class.new(metadata, apis, models)
115
+ expect(declaration.api_version).to eq(metadata.api_version)
116
+ end
117
+ end
118
+ describe "#camelize_model_properties" do
119
+ it "returns metadata.camelize_model_properties" do
120
+ metadata = double("metadata", camelize_model_properties: false)
121
+ declaration = described_class.new(metadata, apis, models)
122
+ expect(declaration.camelize_model_properties).to eq(metadata.camelize_model_properties)
123
+ end
124
+ end
125
+ describe "#models" do
126
+ context "with camelize_model_properties set to true" do
127
+ it "returns a models hash that's ready for output" do
128
+ declaration = described_class.new(metadata, apis, models)
129
+ allow(declaration).to receive(:camelize_model_properties).and_return(true)
130
+ expected_models_hash = {
131
+ "Tag" =>
132
+ {
133
+ "id" => :Tag,
134
+ "required" =>[:id],
135
+ "properties" =>
136
+ {
137
+ "id" =>{"type"=>:integer, "description"=>"User Id"},
138
+ "firstName"=>{"type"=>:string, "description"=>"First Name"},
139
+ "lastName"=>{"type"=>:string, "description"=>"Last Name"},
140
+ },
141
+ "description"=>"A Tag object."
142
+ }
143
+ }
144
+
145
+ expect(declaration.models).to eq(expected_models_hash)
146
+ end
147
+ end
148
+ context "with camelize_model_properties set to false" do
149
+ it "returns a models hash that's ready for output" do
150
+ declaration = described_class.new(metadata, apis, models)
151
+ allow(declaration).to receive(:camelize_model_properties).and_return(false)
152
+ expected_models_hash = {
153
+ "Tag" =>
154
+ {
155
+ "id" => :Tag,
156
+ "required" =>[:id],
157
+ "properties" =>
158
+ {
159
+ "id" =>{"type"=>:integer, "description"=>"User Id"},
160
+ "first_name"=>{"type"=>:string, "description"=>"First Name"},
161
+ "last_name"=>{"type"=>:string, "description"=>"Last Name"},
162
+ },
163
+ "description"=>"A Tag object."
164
+ }
165
+ }
166
+
167
+ expect(declaration.models).to eq(expected_models_hash)
168
+ end
169
+ end
170
+ end
171
+ describe "#apis" do
172
+ it "returns a api hash that's ready for output" do
173
+ declaration = described_class.new(metadata, apis, models)
174
+ expected_apis_array = [
175
+ {
176
+ "path"=>"sample/{id}",
177
+ "operations"=>[
178
+ {
179
+ "summary"=>"Updates an existing User",
180
+ "parameters"=>[
181
+ {"paramType"=>:path, "name"=>:id, "type"=>:integer, "description"=>"User Id", "required"=>true},
182
+ {"paramType"=>:form, "name"=>:first_name, "type"=>:string, "description"=>"First name", "required"=>false},
183
+ {"paramType"=>:form, "name"=>:last_name, "type"=>:string, "description"=>"Last name", "required"=>false},
184
+ {"paramType"=>:form, "name"=>:email, "type"=>:string, "description"=>"Email address", "required"=>false},
185
+ {"paramType"=>:form, "name"=>:tag, "type"=>:Tag, "description"=>"Tag object", "required"=>true}
186
+ ],
187
+ "responseMessages"=>[
188
+ {"code"=>401, "message"=>"Unauthorized"},
189
+ {"code"=>404, "message"=>"Not Found"},
190
+ {"code"=>406, "message"=>"Not Acceptable"}
191
+ ],
192
+ "notes"=>"Only the given fields are updated.",
193
+ "method"=>:put,
194
+ "nickname"=>"Api::V1::Sample#update",
195
+ "consumes"=>["application/json", "text/xml"]
196
+ }
197
+ ]
198
+ }
199
+ ]
200
+ expect(declaration.apis).to eq(expected_apis_array)
201
+ end
202
+ end
203
+ end