swagger_yard 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6dfc1b55809fb818e9c2f1742a741ebbf72eb4d
4
- data.tar.gz: cb8f8253cb95a55c04d6a9cd5b7488ae6d40b47c
3
+ metadata.gz: d61bc284164e43af94017cc989f2dc61ac5a98e2
4
+ data.tar.gz: b312468a3884e80013827ed6e82b5b00fe3539cf
5
5
  SHA512:
6
- metadata.gz: b2c1e0eb8a9461f39d3161f62592c8cdf817f0c1fa9a8d3b9fc8231a171ee30246eb84fb74be727ed1671fde7244d740d5e4b774e5f5d0334c913e15270b7182
7
- data.tar.gz: d47a31030769ce82fb1a7cb5242899562c229ed023c3155f25be48fd5f91a9d8ab7f9c67587073d645a0958d9b3bec7dec2d23ca55b2cf5dcfcca2ce54d90c21
6
+ metadata.gz: efc555082f8433aecca02e2d811943b10e8487701b68632670fd6c8f82b052eb849127d14498c58513e6aece261e9d8ea1cf8ab5b5ea2b5ccc94404d8a585f70
7
+ data.tar.gz: 081c4133f4c53d1845b547229250c5296b60ccee71a46e1c9970a71fdfc941c76701ae8ea63c19ade023f905dd712f14402048f0be234b361d6154d609740a26
data/README.md CHANGED
@@ -23,10 +23,12 @@ Install the gem with Bunder:
23
23
  config.api_version = "1.0"
24
24
  config.reload = Rails.env.development?
25
25
 
26
- # where your swagger spec json will show up
27
- config.swagger_spec_base_path = "http://localhost:3000/swagger/api"
28
26
  # where your actual api is hosted from
29
27
  config.api_base_path = "http://localhost:3000/api"
28
+
29
+ # where your swagger spec json will show up
30
+ # configure this to match SwaggerYard::Rails mount point
31
+ config.swagger_spec_base_path = "http://localhost:3000/swagger/api"
30
32
  end
31
33
 
32
34
  # register swagger tags with YARD
@@ -129,12 +131,31 @@ end
129
131
 
130
132
  ## UI ##
131
133
 
132
- It is advisable to use something like [swagger-ui_rails](https://github.com/3scale/swagger-ui_rails/tree/dev-2.1.3) for your UI needs inside of Rails.
134
+ We suggest using something like [swagger-ui_rails](https://github.com/3scale/swagger-ui_rails/tree/dev-2.1.3) for your UI needs inside of Rails.
135
+
136
+ To generate JSON from your code on request, checkout the [swagger_yard-rails](https://github.com/tpitale/swagger_yard-rails) project. This provides an engine to parse and render the json required for use by swagger-ui_rails.
133
137
 
134
138
  ## More Information ##
135
139
 
136
- * [Swagger-ui](https://github.com/wordnik/swagger-ui)
137
140
  * [swagger-ui_rails](https://github.com/3scale/swagger-ui_rails/tree/dev-2.1.3)
138
- * [Yard](https://github.com/lsegal/yard)
139
- * [Swagger-spec version 1.2](https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md)
141
+ * [swagger_yard-rails](https://github.com/tpitale/swagger_yard-rails)
140
142
  * [Swagger-spec version 2.0](https://github.com/wordnik/swagger-spec/blob/master/versions/2.0.md)
143
+ * [Yard](https://github.com/lsegal/yard)
144
+
145
+ ## Current Parsing "Tree" Structure ##
146
+
147
+ ResourceListing
148
+ |
149
+ -> ApiDeclaration (controller)
150
+ | |
151
+ | -> ListingInfo (controller class)
152
+ | -> Authorization (header/param for auth, also added to ResourceListing?)
153
+ | -> Api(s) (controller action, by path)
154
+ | |
155
+ | -> Operation(s) (controller action with HTTP method)
156
+ | |
157
+ | -> Parameter(s) (action param)
158
+ |
159
+ -> Model (model)
160
+ |
161
+ -> Properties (model attributes)
@@ -11,6 +11,7 @@ require "swagger_yard/api_declaration"
11
11
  require "swagger_yard/model"
12
12
  require "swagger_yard/api"
13
13
  require "swagger_yard/listing_info"
14
+ require "swagger_yard/swagger"
14
15
 
15
16
  module SwaggerYard
16
17
  class << self
@@ -44,10 +45,6 @@ module SwaggerYard
44
45
  ::YARD::Registry.all
45
46
  end
46
47
 
47
- def yard_objects_from_resource(resource_name)
48
- yard_objects_from_file(resource_to_file_path[resource_name])
49
- end
50
-
51
48
  ##
52
49
  # Register some custom yard tags used by swagger-ui
53
50
  def register_custom_yard_tags!
@@ -1,6 +1,6 @@
1
1
  module SwaggerYard
2
2
  class Api
3
- attr_accessor :path, :description
3
+ attr_accessor :path, :description, :operations, :api_declaration
4
4
 
5
5
  def self.path_from_yard_object(yard_object)
6
6
  if tag = yard_object.tags.detect {|t| t.tag_name == "path"}
@@ -29,21 +29,16 @@ module SwaggerYard
29
29
  @operations << Operation.from_yard_object(yard_object, self)
30
30
  end
31
31
 
32
- def to_h
33
- {
34
- "path" => path,
35
- "description" => description,
36
- "operations" => @operations.map(&:to_h)
37
- }
38
- end
39
-
40
32
  def model_names
41
33
  @operations.map(&:model_names).flatten.compact.uniq
42
- # @parameters.select {|p| ref?(p['type'])}.map {|p| p['type']}.uniq
43
34
  end
44
35
 
45
36
  def ref?(data_type)
46
37
  @api_declaration.ref?(data_type)
47
38
  end
39
+
40
+ def operations_hash
41
+ Hash[@operations.map {|op| [op.http_method.downcase, op.to_h]}]
42
+ end
48
43
  end
49
- end
44
+ end
@@ -1,6 +1,6 @@
1
1
  module SwaggerYard
2
2
  class ApiDeclaration
3
- attr_accessor :description, :resource_path
3
+ attr_accessor :description, :resource, :resource_path
4
4
  attr_reader :apis, :authorizations
5
5
 
6
6
  def initialize(resource_listing)
@@ -23,17 +23,18 @@ module SwaggerYard
23
23
 
24
24
  def add_yard_object(yard_object)
25
25
  case yard_object.type
26
- when :class
26
+ when :class # controller
27
27
  add_listing_info(ListingInfo.new(yard_object))
28
28
  add_authorizations_to_resource_listing(yard_object)
29
- when :method
29
+ when :method # actions
30
30
  add_api(yard_object)
31
31
  end
32
32
  end
33
33
 
34
34
  def add_listing_info(listing_info)
35
- @description = listing_info.description
36
- @resource_path = listing_info.resource_path
35
+ @description = listing_info.description
36
+ @resource = listing_info.resource
37
+ @resource_path = listing_info.resource_path # required for valid? but nothing else
37
38
 
38
39
  # we only have api_key auth, the value for now is always empty array
39
40
  @authorizations = Hash[listing_info.authorizations.uniq.map {|k| [k, []]}]
@@ -67,23 +68,13 @@ module SwaggerYard
67
68
  @resource_listing.models.map(&:id).include?(name)
68
69
  end
69
70
 
70
- def to_h
71
- {
72
- "apiVersion" => SwaggerYard.config.api_version,
73
- "swaggerVersion" => SwaggerYard.config.swagger_version,
74
- "basePath" => SwaggerYard.config.api_base_path,
75
- "resourcePath" => resource_path,
76
- "apis" => apis.values.map(&:to_h),
77
- "models" => Hash[models.map {|m| [m.id, m.to_h]}],
78
- "authorizations" => authorizations
79
- }
71
+ def apis_hash
72
+ Hash[apis.map {|path, api| [path, api.operations_hash]}]
80
73
  end
81
74
 
82
- def listing_hash
83
- {
84
- "path" => resource_path,
85
- "description" => description
86
- }
75
+ def to_tag
76
+ { "name" => resource,
77
+ "description" => description }
87
78
  end
88
79
 
89
80
  private
@@ -26,11 +26,9 @@ module SwaggerYard
26
26
  end
27
27
 
28
28
  def to_h
29
- {
30
- "type" => type,
31
- "passAs" => @pass_as,
32
- "keyname" => @key
33
- }
29
+ { "type" => type,
30
+ "name" => @key,
31
+ "in" => @pass_as }
34
32
  end
35
33
  end
36
34
  end
@@ -2,13 +2,17 @@ module SwaggerYard
2
2
  class Configuration
3
3
  attr_accessor :swagger_spec_base_path, :api_base_path, :api_path
4
4
  attr_accessor :swagger_version, :api_version
5
+ attr_accessor :title, :description
5
6
  attr_accessor :enable, :reload
7
+ attr_accessor :controller_path, :model_path
6
8
 
7
9
  def initialize
8
10
  self.swagger_version = "1.1"
9
11
  self.api_version = "0.1"
10
12
  self.enable = false
11
13
  self.reload = true
14
+ self.title = "Configure title with SwaggerYard.config.title"
15
+ self.description = "Configure description with SwaggerYard.config.description"
12
16
  end
13
17
  end
14
- end
18
+ end
@@ -1,10 +1,14 @@
1
1
  module SwaggerYard
2
2
  class ListingInfo
3
- attr_reader :description, :resource_path, :authorizations
3
+ attr_reader :description, :resource, :resource_path, :authorizations
4
4
 
5
5
  def initialize(yard_object)
6
6
  @description = yard_object.docstring
7
7
 
8
+ if tag = yard_object.tags.detect {|t| t.tag_name == "resource"}
9
+ @resource = tag.text
10
+ end
11
+
8
12
  if tag = yard_object.tags.detect {|t| t.tag_name == "resource_path"}
9
13
  @resource_path = tag.text.downcase
10
14
  end
@@ -57,13 +57,10 @@ module SwaggerYard
57
57
  end
58
58
 
59
59
  def to_h
60
- raise "Model is missing @model tag" if id.nil?
61
-
62
- {
63
- "id" => id,
64
- "properties" => Hash[@properties.map {|property| [property.name, property.to_h]}],
65
- "required" => @properties.select(&:required?).map(&:name)
66
- }
60
+ {}.tap do |h|
61
+ h["properties"] = Hash[@properties.map {|p| [p.name, p.to_h]}]
62
+ h["required"] = @properties.select(&:required?).map(&:name) if @properties.detect(&:required?)
63
+ end
67
64
  end
68
65
  end
69
66
  end
@@ -1,6 +1,6 @@
1
1
  module SwaggerYard
2
2
  class Operation
3
- attr_accessor :summary, :notes
3
+ attr_accessor :summary, :notes, :ruby_method
4
4
  attr_reader :path, :http_method, :error_messages, :response_type
5
5
  attr_reader :parameters, :model_names
6
6
 
@@ -9,6 +9,7 @@ module SwaggerYard
9
9
  # TODO: extract to operation builder?
10
10
  def self.from_yard_object(yard_object, api)
11
11
  new(api).tap do |operation|
12
+ operation.ruby_method = yard_object.name(false)
12
13
  yard_object.tags.each do |tag|
13
14
  case tag.tag_name
14
15
  when "path"
@@ -45,17 +46,37 @@ module SwaggerYard
45
46
  end
46
47
 
47
48
  def to_h
49
+ method = http_method.downcase
50
+ description = notes || ""
51
+ params = parameters.map(&:to_h)
52
+ responses = { "default" => { "description" => summary || @api.description } }
53
+
54
+ if response_type
55
+ responses["default"]["schema"] = response_type.to_h
56
+ end
57
+
58
+ unless error_messages.empty?
59
+ error_messages.each do |err|
60
+ responses[err["code"].to_s] = {}.tap do |h|
61
+ h["description"] = err["message"]
62
+ h["schema"] = Type.from_type_list(Array(err["responseModel"])).to_h if err["responseModel"]
63
+ end
64
+ end
65
+ end
66
+
48
67
  {
49
- "httpMethod" => http_method,
50
- "nickname" => nickname,
51
- "type" => "void",
52
- "produces" => ["application/json", "application/xml"],
53
- "parameters" => parameters.map(&:to_h),
54
- "summary" => summary || @api.description,
55
- "notes" => notes,
56
- "responseMessages" => error_messages
68
+ "summary" => summary || @api.description,
69
+ "tags" => [@api.api_declaration.resource].compact,
70
+ "operationId" => "#{@api.api_declaration.resource}-#{ruby_method}",
71
+ "parameters" => params,
72
+ "responses" => responses,
57
73
  }.tap do |h|
58
- h.merge!(response_type.to_h) if response_type
74
+ h["description"] = description unless description.to_s.empty?
75
+
76
+ authorizations = @api.api_declaration.authorizations
77
+ unless authorizations.empty?
78
+ h["security"] = authorizations.map {|k,v| { k => v} }
79
+ end
59
80
  end
60
81
  end
61
82
 
@@ -55,14 +55,21 @@ module SwaggerYard
55
55
  end
56
56
 
57
57
  def to_h
58
- {
59
- "paramType" => param_type,
60
- "name" => name,
61
- "description" => description,
62
- "required" => required,
63
- "allowMultiple" => !!allow_multiple,
64
- "allowableValues" => allowable_values_hash
65
- }.merge(@type.to_h).reject {|k,v| v.nil?}
58
+ { "name" => name,
59
+ "description" => description,
60
+ "required" => required,
61
+ "in" => param_type
62
+ }.tap do |h|
63
+ if !Array(allowable_values).empty?
64
+ h["enum"] = allowable_values
65
+ end
66
+ if h["in"] == "body"
67
+ h["schema"] = @type.to_h
68
+ else
69
+ h.update(@type.to_h)
70
+ end
71
+ h["collectionFormat"] = 'multi' if !Array(allow_multiple).empty? && h["items"]
72
+ end
66
73
  end
67
74
  end
68
- end
75
+ end
@@ -28,9 +28,9 @@ module SwaggerYard
28
28
  end
29
29
 
30
30
  def to_h
31
- result = @type.to_h
32
- result["description"] = description if description
33
- result
31
+ @type.to_h.tap do |h|
32
+ h["description"] = description if description
33
+ end
34
34
  end
35
35
  end
36
36
  end
@@ -1,8 +1,11 @@
1
1
  module SwaggerYard
2
2
  class ResourceListing
3
- attr_reader :api_declarations, :resource_to_file_path
4
3
  attr_accessor :authorizations
5
4
 
5
+ def self.all
6
+ new(SwaggerYard.config.controller_path, SwaggerYard.config.model_path)
7
+ end
8
+
6
9
  def initialize(controller_path, model_path)
7
10
  @model_path = model_path
8
11
  @controller_path = controller_path
@@ -19,25 +22,33 @@ module SwaggerYard
19
22
  @controllers ||= parse_controllers
20
23
  end
21
24
 
22
- def declaration_for(resource_name)
23
- controllers[resource_name]
25
+ def to_h
26
+ { "paths" => path_objects,
27
+ "definitions" => model_objects,
28
+ "tags" => tag_objects,
29
+ "securityDefinitions" => security_objects }
30
+ end
31
+
32
+ def path_objects
33
+ controllers.map(&:apis_hash).inject({}) do |h, api_hash|
34
+ h.merge api_hash
35
+ end
24
36
  end
25
37
 
26
- def to_h
27
- {
28
- "apiVersion" => SwaggerYard.config.api_version,
29
- "swaggerVersion" => SwaggerYard.config.swagger_version,
30
- "basePath" => SwaggerYard.config.swagger_spec_base_path,
31
- "apis" => list_api_declarations,
32
- "authorizations" => authorizations_hash
33
- }
38
+ # Resources
39
+ def tag_objects
40
+ controllers.map(&:to_tag)
34
41
  end
35
42
 
36
- private
37
- def list_api_declarations
38
- controllers.values.sort_by(&:resource_path).map(&:listing_hash)
43
+ def model_objects
44
+ Hash[models.map {|m| [m.id, m.to_h]}]
39
45
  end
40
46
 
47
+ def security_objects
48
+ Hash[authorizations.map {|auth| [auth.name, auth.to_h]}]
49
+ end
50
+
51
+ private
41
52
  def parse_models
42
53
  return [] unless @model_path
43
54
 
@@ -47,13 +58,11 @@ module SwaggerYard
47
58
  end
48
59
 
49
60
  def parse_controllers
50
- return {} unless @controller_path
51
-
52
- Hash[Dir[@controller_path].map do |file_path|
53
- declaration = create_api_declaration(file_path)
61
+ return [] unless @controller_path
54
62
 
55
- [declaration.resource_name, declaration] if declaration.valid?
56
- end.compact]
63
+ Dir[@controller_path].map do |file_path|
64
+ create_api_declaration(file_path)
65
+ end.select(&:valid?)
57
66
  end
58
67
 
59
68
  def create_api_declaration(file_path)
@@ -61,11 +70,5 @@ module SwaggerYard
61
70
 
62
71
  ApiDeclaration.new(self).add_yard_objects(yard_objects)
63
72
  end
64
-
65
- def authorizations_hash
66
- Hash[
67
- authorizations.map(&:name).zip(authorizations.map(&:to_h)) # ugh
68
- ]
69
- end
70
73
  end
71
74
  end
@@ -0,0 +1,19 @@
1
+ module SwaggerYard
2
+ class Info
3
+ def to_h
4
+ { "title" => SwaggerYard.config.title,
5
+ "description" => SwaggerYard.config.description,
6
+ "version" => SwaggerYard.config.api_version }
7
+ end
8
+ end
9
+
10
+ class Swagger
11
+ def to_h
12
+ { "swagger" => "2.0",
13
+ "info" => Info.new.to_h,
14
+ "host" => URI(SwaggerYard.config.api_base_path).host,
15
+ "basePath" => URI(SwaggerYard.config.api_base_path).request_uri
16
+ }.merge(ResourceListing.all.to_h)
17
+ end
18
+ end
19
+ end
@@ -22,12 +22,32 @@ module SwaggerYard
22
22
 
23
23
  alias :array? :array
24
24
 
25
+ def json_type
26
+ type, format = name, nil
27
+ case name
28
+ when "float", "double"
29
+ type = "number"
30
+ format = name
31
+ when "date-time", "date", "time"
32
+ type = "string"
33
+ format = name
34
+ end
35
+ {}.tap do |h|
36
+ h["type"] = type
37
+ h["format"] = format if format
38
+ end
39
+ end
40
+
25
41
  def to_h
26
- type_tag = ref? ? "$ref" : "type"
42
+ type = if ref?
43
+ { "$ref" => "#/definitions/#{name}"}
44
+ else
45
+ json_type
46
+ end
27
47
  if array?
28
- {"type"=>"array", "items"=> { type_tag => name }}
48
+ { "type" => "array", "items" => type }
29
49
  else
30
- {"type"=>name}
50
+ type
31
51
  end
32
52
  end
33
53
  end
@@ -1,3 +1,3 @@
1
1
  module SwaggerYard
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swagger_yard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - chtrinh (Chris Trinh)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-15 00:00:00.000000000 Z
11
+ date: 2015-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-its
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: apivore
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: simplecov
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +133,6 @@ files:
105
133
  - MIT-LICENSE
106
134
  - README.md
107
135
  - Rakefile
108
- - config/routes.rb
109
136
  - lib/swagger_yard.rb
110
137
  - lib/swagger_yard/api.rb
111
138
  - lib/swagger_yard/api_declaration.rb
@@ -117,6 +144,7 @@ files:
117
144
  - lib/swagger_yard/parameter.rb
118
145
  - lib/swagger_yard/property.rb
119
146
  - lib/swagger_yard/resource_listing.rb
147
+ - lib/swagger_yard/swagger.rb
120
148
  - lib/swagger_yard/type.rb
121
149
  - lib/swagger_yard/version.rb
122
150
  homepage: http://www.synctv.com
@@ -1,6 +0,0 @@
1
- SwaggerYard::Engine.routes.draw do
2
- get '/doc', to: 'swagger#doc'
3
-
4
- get '/api', to: 'swagger#index'
5
- get '/api/*resource', to: 'swagger#show'
6
- end