swagui 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/Gemfile +6 -0
- data/Guardfile +10 -0
- data/README.md +61 -1
- data/Rakefile +7 -0
- data/lib/swagui.rb +16 -4
- data/lib/swagui/asset_handler.rb +3 -0
- data/lib/swagui/json_schema.rb +38 -0
- data/lib/swagui/json_schema_parser.rb +11 -0
- data/lib/swagui/swagger_doc_handler.rb +9 -20
- data/lib/swagui/version.rb +1 -1
- data/lib/swagui/yaml_doc_handler.rb +81 -0
- data/test/test_helper.rb +15 -0
- data/test/test_json_schema.rb +21 -0
- data/test/test_json_schema_parser.rb +14 -0
- data/test/test_swagger_doc_handler.rb +28 -0
- metadata +15 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ece6a30df668aa10a6f7414e3acb9b533336385
|
4
|
+
data.tar.gz: 812dce9d3d9fb20f887928ea8a3205173905412e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9745d126ccea6472f6adb5ac06d879ce0a0d276b6331c7f3a67a473a5f74deac6d6d6302aee290ca842cffb6dc163f3d572d22dca38a376275adcc1e7f843b
|
7
|
+
data.tar.gz: 208d92bf9221669eac16e35ef8bb9b268614091e31f828bef6023c4f33b9a58d69f561a9c2a1f7577c95cd4dd490b5a7cc8c58f7379d6f7c87ee48ca9151cd5b
|
data/Gemfile
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
interactor :simple
|
5
|
+
guard 'jruby-minitest', :spec_paths => ["test"], :all_on_start => false do
|
6
|
+
watch(%r{^test/(.*)\/?test_(.*)\.rb$})
|
7
|
+
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/test_#{m[2]}.rb" }
|
8
|
+
watch(%r{^test/test_helper\.rb$}) { 'test' }
|
9
|
+
end
|
10
|
+
|
data/README.md
CHANGED
@@ -35,6 +35,65 @@ end
|
|
35
35
|
|
36
36
|
You will be able to access the [swagger-ui] loaded with your api documentation at `/doc` (your `url` setting) when the server starts.
|
37
37
|
|
38
|
+
### doc file format
|
39
|
+
|
40
|
+
`Swagui` supports three types of doc format
|
41
|
+
|
42
|
+
1. JSON documents with no extension ([original swagger doc format]), such as `api-docs` and `account`.
|
43
|
+
2. JSON documents with `.json` extension, such as `api-docs.json` and `account.json`.
|
44
|
+
3. YAML documents. This the recommended approach as it is naturally more concise than json and also tries to be more opinionated in the following ways:
|
45
|
+
1. if not provided in `api-docs.yml`, the list of apis under `apis` is automatically populated by the names of all the .yml files in the same directory.
|
46
|
+
2. the `basePath` attribute of each doc, used for `try it out` feature, if unprovided, is automatically provided based on the host application. this assumes the doc is hosted as part of the application.
|
47
|
+
3. to circumvent all the rather complex and tedious syntax for `models`, schema attributes under `apis/operations/parameters` (for request body json schema) and `apis/operations/responseMessages` (for response body json schema), and it will be used to automatically populate the `models` under root.
|
48
|
+
|
49
|
+
With this approach, swagger api docs are now a lot more concise and readible, let alone having dynamic `basePath`.
|
50
|
+
|
51
|
+
#### sample api-docs.yml
|
52
|
+
```yaml
|
53
|
+
---
|
54
|
+
info:
|
55
|
+
title: "a sojourner's api"
|
56
|
+
description: "Ut? Amet, et eros nascetur parturient diam scelerisque, egestas, pulvinar sit cum, rhoncus eros vel urna aliquam massa! Turpis purus auctor proin aliquam nunc, nec proin vel enim est, scelerisque! Ac vel integer proin sed in."
|
57
|
+
contact: "sojourner@world.net"
|
58
|
+
apiVersion: "1.0.0"
|
59
|
+
swaggerVersion: "1.2"
|
60
|
+
authorizations: {}
|
61
|
+
|
62
|
+
```
|
63
|
+
#### sample account.yml
|
64
|
+
```yaml
|
65
|
+
---
|
66
|
+
produces:
|
67
|
+
- application/json
|
68
|
+
apis:
|
69
|
+
-
|
70
|
+
path: /account
|
71
|
+
description: create or update a account
|
72
|
+
operations:
|
73
|
+
-
|
74
|
+
method: POST
|
75
|
+
summary: create or update an account
|
76
|
+
nickname: PostAccount
|
77
|
+
parameters:
|
78
|
+
-
|
79
|
+
name: body
|
80
|
+
required: true
|
81
|
+
schema: test/doc/schemas/account_post_request_body.schema.json
|
82
|
+
paramType: body
|
83
|
+
responseMessages:
|
84
|
+
-
|
85
|
+
code: 200
|
86
|
+
message: account creation success
|
87
|
+
schema: test/doc/schemas/account_post_creation_success.schema.json
|
88
|
+
-
|
89
|
+
code: 400
|
90
|
+
message: account creation failure
|
91
|
+
schema: test/doc/schemas/account_post_creation_failure.schema.json
|
92
|
+
|
93
|
+
```
|
94
|
+
|
95
|
+
|
96
|
+
|
38
97
|
### Command-line utility
|
39
98
|
|
40
99
|
Sometimes, you only want to see the documentation without starting the entire application. All you need to do is to run the following command in your documentation directory:
|
@@ -48,7 +107,7 @@ optionally, you can specify the directory name as a command line argument:
|
|
48
107
|
You will then able to view the [swagger-ui] loaded with your api documentation at `http://localhost:9292`
|
49
108
|
|
50
109
|
[swagger-ui]: https://github.com/wordnik/swagger-ui
|
51
|
-
|
110
|
+
[original swagger doc format]: https://github.com/wordnik/swagger-spec/blob/master/fixtures/v1.2/helloworld/static/api-docs
|
52
111
|
## Contributing
|
53
112
|
|
54
113
|
1. Fork it ( https://github.com/jackxxu/swagui/fork )
|
@@ -56,3 +115,4 @@ You will then able to view the [swagger-ui] loaded with your api documentation a
|
|
56
115
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
57
116
|
4. Push to the branch (`git push origin my-new-feature`)
|
58
117
|
5. Create a new Pull Request
|
118
|
+
|
data/Rakefile
CHANGED
data/lib/swagui.rb
CHANGED
@@ -1,4 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'swagui/version'
|
2
|
+
require 'swagui/app'
|
3
|
+
require 'swagui/asset_handler'
|
4
|
+
require 'swagui/swagger_doc_handler'
|
5
|
+
require 'swagui/yaml_doc_handler'
|
6
|
+
require 'swagui/json_schema_parser'
|
7
|
+
require 'swagui/json_schema'
|
8
|
+
|
9
|
+
|
10
|
+
module Swagui
|
11
|
+
|
12
|
+
def self.file_full_path(relative_path)
|
13
|
+
File.expand_path(relative_path, Dir.pwd)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/lib/swagui/asset_handler.rb
CHANGED
@@ -4,6 +4,9 @@ module Swagui
|
|
4
4
|
def initialize(path)
|
5
5
|
@url_regex = Regexp.union(Regexp.new("^\/swagger-ui"), Regexp.new("^#{path}\/?$"))
|
6
6
|
swagger_ui_dir = File.expand_path('../../swagger-ui', File.dirname(__FILE__))
|
7
|
+
|
8
|
+
raise "swagger ui assets directory #{swagger_ui_dir} does not exist" unless File.directory?(swagger_ui_dir)
|
9
|
+
|
7
10
|
@asset_file_server = Rack::File.new(swagger_ui_dir)
|
8
11
|
end
|
9
12
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Swagui
|
2
|
+
class JsonSchema
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize(schema_hash, name)
|
7
|
+
@name = name
|
8
|
+
@schema_hash = schema_hash
|
9
|
+
@nested_objects = []
|
10
|
+
|
11
|
+
@schema_hash['properties'].each do |pname, pattributes|
|
12
|
+
if pattributes['type'] == 'object'
|
13
|
+
nested_object_name = "#{@name}-#{pname}"
|
14
|
+
@schema_hash['properties'][pname] = {'$ref' => nested_object_name }
|
15
|
+
@nested_objects << JsonSchema.new(pattributes, nested_object_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def properties
|
21
|
+
@schema_hash['properties']
|
22
|
+
end
|
23
|
+
|
24
|
+
def models
|
25
|
+
all_objects.map do |schema|
|
26
|
+
{
|
27
|
+
'id' => schema.name,
|
28
|
+
'properties' => schema.properties
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def all_objects
|
34
|
+
([self] + @nested_objects.map {|x| x.all_objects}).flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -2,8 +2,11 @@ module Swagui
|
|
2
2
|
class SwaggerDocHandler
|
3
3
|
def initialize(path, url)
|
4
4
|
@url_regex = Regexp.new("^#{url}")
|
5
|
-
app_doc_dir =
|
6
|
-
|
5
|
+
app_doc_dir = Swagui.file_full_path(path || url)
|
6
|
+
|
7
|
+
raise "swagger api doc directory #{app_doc_dir} does not exist" unless File.directory?(app_doc_dir)
|
8
|
+
|
9
|
+
@app_file_server = YAMLDocHandler.new(Rack::File.new(app_doc_dir))
|
7
10
|
end
|
8
11
|
|
9
12
|
def handles?(env)
|
@@ -13,26 +16,12 @@ module Swagui
|
|
13
16
|
def call(env)
|
14
17
|
path = env["PATH_INFO"].gsub(@url_regex, '') # root path renders index.html
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
body = ''
|
20
|
-
response[2].each {|f| body = YAML::load(f).to_json}
|
21
|
-
response[2] = [body]
|
22
|
-
response[1].merge!("Content-Length"=> body.size.to_s)
|
23
|
-
end
|
19
|
+
first_valid_file_response = ['', '.json', '.yml'].map do |ext|
|
20
|
+
@app_file_server.call(env.merge('PATH_INFO' => "#{path}#{ext}", 'REQUEST_METHOD' => 'GET'))
|
21
|
+
end.find {|res| res[0] == 200 }
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
response
|
23
|
+
first_valid_file_response || [404, {"Content-Type"=>"application/json"}, '']
|
28
24
|
end
|
29
25
|
|
30
|
-
private
|
31
|
-
|
32
|
-
def first_valid_file_response(path)
|
33
|
-
['', '.json', '.yml'].map do |ext|
|
34
|
-
@app_file_server.call('PATH_INFO' => "#{path}#{ext}", 'REQUEST_METHOD' => 'GET')
|
35
|
-
end.find {|res| res[0] == 200 }
|
36
|
-
end
|
37
26
|
end
|
38
27
|
end
|
data/lib/swagui/version.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Swagui
|
4
|
+
class YAMLDocHandler
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
@app.call(env).tap do |response|
|
12
|
+
|
13
|
+
response[1].merge!("Content-Type"=>"application/json") # response is always json content
|
14
|
+
|
15
|
+
if yaml_response?(response) # yml response needs to be re=processed.
|
16
|
+
body = []
|
17
|
+
response[2].each do |f|
|
18
|
+
body << YAML::load(f).tap do |response_hash|
|
19
|
+
process_schemas(response_hash)
|
20
|
+
process_api_docs_api_listing(response_hash, response[2].path )
|
21
|
+
process_base_path(response_hash, response[2].path, env)
|
22
|
+
end.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
response[2] = body
|
26
|
+
|
27
|
+
response[1].merge!("Content-Length"=> body.first.size.to_s)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def yaml_response?(response)
|
35
|
+
response[2].respond_to?(:path) && response[2].path.end_with?('.yml')
|
36
|
+
end
|
37
|
+
|
38
|
+
def process_schemas(response_hash)
|
39
|
+
(response_hash['apis'] || []).each do |api_hash|
|
40
|
+
(api_hash['operations'] || []).each do |operations_hash|
|
41
|
+
(operations_hash['parameters'] || []).each do |parameters_hash|
|
42
|
+
if schema_file = parameters_hash.delete('schema')
|
43
|
+
schema_file_path = Swagui.file_full_path(schema_file)
|
44
|
+
schema = JsonSchemaParser.parse(schema_file_path, "#{operations_hash['nickname']}-Request")
|
45
|
+
schema.models.each {|m| (response_hash['models'] ||= {})[m['id']] = m }
|
46
|
+
parameters_hash.merge!('type' => schema.name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
operations_hash['responseMessages'].each do |response_messages_hash|
|
50
|
+
if schema_file = response_messages_hash.delete('schema')
|
51
|
+
schema_file_path = Swagui.file_full_path(schema_file)
|
52
|
+
schema = JsonSchemaParser.parse(schema_file_path, "#{operations_hash['nickname']}-Response-#{response_messages_hash['message'].gsub(' ', '-')}")
|
53
|
+
schema.models.each {|m| (response_hash['models'] ||= {})[m['id']] = m }
|
54
|
+
response_messages_hash.merge!('responseModel' => schema.name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def process_api_docs_api_listing(response_hash, doc_path)
|
62
|
+
if doc_path.end_with?('api-docs.yml') && response_hash['models'].nil? # requesting the root
|
63
|
+
dir_path = File.dirname(doc_path)
|
64
|
+
files = Dir["#{File.dirname(doc_path)}/*.yml"].map {|x| x.gsub(dir_path, '').gsub('.yml', '')}
|
65
|
+
files.each do |file|
|
66
|
+
unless file == '/api-docs'
|
67
|
+
(response_hash['apis'] ||= []) << {'path' => "/..#{file}"}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def process_base_path(response_hash, doc_path, env)
|
74
|
+
if !doc_path.end_with?('api-docs.yml') && response_hash['basePath'].nil?
|
75
|
+
request = Rack::Request.new(env)
|
76
|
+
response_hash['basePath'] = (request.base_url + request.script_name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
Bundler.require(:default, :test)
|
4
|
+
|
5
|
+
require 'swagui'
|
6
|
+
require 'rack/lobster'
|
7
|
+
require 'json'
|
8
|
+
class Minitest::Test
|
9
|
+
def mounted_app
|
10
|
+
Rack::Builder.new do
|
11
|
+
use Swagui::App, url: '/doc', path: 'test/doc'
|
12
|
+
run Rack::Lobster.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestJsonSchema < Minitest::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
sampole_schema_file = File.expand_path('doc/schemas/account_post_request_body.schema.json', File.dirname(__FILE__))
|
7
|
+
@schema_json = JSON.load(File.open(sampole_schema_file).read)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_objects_method_returns_array
|
11
|
+
schema = Swagui::JsonSchema.new(@schema_json, 'PostAccount')
|
12
|
+
assert_equal schema.all_objects.size, 2
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_models_methods_return_array_of_hash
|
16
|
+
schema = Swagui::JsonSchema.new(@schema_json, 'PostAccount')
|
17
|
+
assert_equal schema.models.size, 2
|
18
|
+
assert_equal schema.models.map {|x| x['id']}, ['PostAccount', 'PostAccount-contact']
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestJsonSchemaParser < Minitest::Test
|
4
|
+
|
5
|
+
def test_parse_file
|
6
|
+
file_path = File.expand_path('test/doc/schemas/account_post_request_body.schema.json', Dir.pwd)
|
7
|
+
result = Swagui::JsonSchemaParser.parse(file_path, 'PostAccount')
|
8
|
+
assert_equal result.class, Swagui::JsonSchema
|
9
|
+
assert_equal result.name, 'PostAccount'
|
10
|
+
assert_equal result.models.size, 2
|
11
|
+
assert_equal result.models.first.class, Hash
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestSwaggerDocHandler < Minitest::Test
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
Rack::Lint.new(mounted_app)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_loading_api_docs_root
|
12
|
+
get '/doc/api-docs'
|
13
|
+
assert last_response.ok?
|
14
|
+
response_json = JSON.parse(last_response.body)
|
15
|
+
assert_equal response_json['apis'].size, 1
|
16
|
+
assert_equal response_json['apis'].first['path'], '/../account'
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_loading_individual_api_doc
|
20
|
+
get '/doc/account'
|
21
|
+
assert last_response.ok?
|
22
|
+
response_json = JSON.parse(last_response.body)
|
23
|
+
assert_equal response_json['apis'].size, 1
|
24
|
+
assert response_json['models'].size > 1
|
25
|
+
assert_equal response_json['models'].keys.first, 'PostAccount-Request'
|
26
|
+
refute response_json['basePath'].nil?
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swagui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Xu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -62,6 +62,7 @@ extra_rdoc_files: []
|
|
62
62
|
files:
|
63
63
|
- .gitignore
|
64
64
|
- Gemfile
|
65
|
+
- Guardfile
|
65
66
|
- LICENSE.txt
|
66
67
|
- README.md
|
67
68
|
- Rakefile
|
@@ -69,8 +70,11 @@ files:
|
|
69
70
|
- lib/swagui.rb
|
70
71
|
- lib/swagui/app.rb
|
71
72
|
- lib/swagui/asset_handler.rb
|
73
|
+
- lib/swagui/json_schema.rb
|
74
|
+
- lib/swagui/json_schema_parser.rb
|
72
75
|
- lib/swagui/swagger_doc_handler.rb
|
73
76
|
- lib/swagui/version.rb
|
77
|
+
- lib/swagui/yaml_doc_handler.rb
|
74
78
|
- swagger-ui/css/reset.css
|
75
79
|
- swagger-ui/css/screen.css
|
76
80
|
- swagger-ui/images/explorer_icons.png
|
@@ -95,6 +99,10 @@ files:
|
|
95
99
|
- swagger-ui/swagger-ui.js
|
96
100
|
- swagger-ui/swagger-ui.min.js
|
97
101
|
- swagui.gemspec
|
102
|
+
- test/test_helper.rb
|
103
|
+
- test/test_json_schema.rb
|
104
|
+
- test/test_json_schema_parser.rb
|
105
|
+
- test/test_swagger_doc_handler.rb
|
98
106
|
homepage: https://github.com/jackxxu/swagui
|
99
107
|
licenses:
|
100
108
|
- MIT
|
@@ -119,4 +127,8 @@ rubygems_version: 2.2.2
|
|
119
127
|
signing_key:
|
120
128
|
specification_version: 4
|
121
129
|
summary: A rack-based swagger-ui middleware and commandline utility.
|
122
|
-
test_files:
|
130
|
+
test_files:
|
131
|
+
- test/test_helper.rb
|
132
|
+
- test/test_json_schema.rb
|
133
|
+
- test/test_json_schema_parser.rb
|
134
|
+
- test/test_swagger_doc_handler.rb
|