grape-swagger 0.7.2 → 0.8.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 +7 -0
- data/.gitignore +33 -0
- data/.rubocop.yml +36 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +90 -0
- data/CONTRIBUTING.md +126 -0
- data/Gemfile +1 -21
- data/LICENSE.txt +1 -1
- data/README.md +397 -0
- data/RELEASING.md +80 -0
- data/Rakefile +6 -23
- data/UPGRADING.md +47 -0
- data/grape-swagger.gemspec +26 -84
- data/lib/grape-swagger.rb +237 -111
- data/lib/grape-swagger/errors.rb +9 -0
- data/lib/grape-swagger/markdown.rb +23 -0
- data/lib/grape-swagger/markdown/kramdown_adapter.rb +37 -0
- data/lib/grape-swagger/markdown/redcarpet_adapter.rb +89 -0
- data/lib/grape-swagger/version.rb +3 -0
- data/spec/api_description_spec.rb +41 -0
- data/spec/api_global_models_spec.rb +76 -0
- data/spec/api_models_spec.rb +190 -93
- data/spec/default_api_spec.rb +31 -36
- data/spec/form_params_spec.rb +56 -53
- data/spec/grape-swagger_helper_spec.rb +88 -49
- data/spec/grape-swagger_spec.rb +7 -5
- data/spec/hide_api_spec.rb +58 -55
- data/spec/markdown/kramdown_adapter_spec.rb +38 -0
- data/spec/markdown/markdown_spec.rb +27 -0
- data/spec/markdown/redcarpet_adapter_spec.rb +81 -0
- data/spec/namespaced_api_spec.rb +47 -0
- data/spec/non_default_api_spec.rb +372 -222
- data/spec/response_model_spec.rb +80 -0
- data/spec/simple_mounted_api_spec.rb +113 -118
- data/spec/spec_helper.rb +0 -1
- data/spec/version_spec.rb +8 -0
- data/test/api.rb +62 -0
- data/test/config.ru +10 -2
- data/test/splines.png +0 -0
- metadata +145 -91
- data/.rvmrc +0 -48
- data/CHANGELOG.markdown +0 -55
- data/Gemfile.lock +0 -94
- data/README.markdown +0 -168
- data/VERSION +0 -1
- data/test/nested_api.rb +0 -30
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'responseModel' do
|
4
|
+
before :all do
|
5
|
+
module MyAPI
|
6
|
+
module Entities
|
7
|
+
class BaseEntity < Grape::Entity
|
8
|
+
def self.entity_name
|
9
|
+
name.sub(/^MyAPI::Entities::/, '')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Something < BaseEntity
|
14
|
+
expose :text, documentation: { type: 'string', desc: 'Content of something.' }
|
15
|
+
end
|
16
|
+
|
17
|
+
class Error < BaseEntity
|
18
|
+
expose :code, documentation: { type: 'string', desc: 'Error code' }
|
19
|
+
expose :message, documentation: { type: 'string', desc: 'Error message' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ResponseModelApi < Grape::API
|
24
|
+
format :json
|
25
|
+
desc 'This returns something or an error',
|
26
|
+
entity: Entities::Something,
|
27
|
+
http_codes: [
|
28
|
+
[200, 'OK', Entities::Something],
|
29
|
+
[403, 'Refused to return something', Entities::Error]
|
30
|
+
]
|
31
|
+
|
32
|
+
get '/something/:id' do
|
33
|
+
if params[:id] == 1
|
34
|
+
something = OpenStruct.new text: 'something'
|
35
|
+
present something, with: Entities::Something
|
36
|
+
else
|
37
|
+
error = OpenStruct.new code: 'some_error', message: 'Some error'
|
38
|
+
present error, with: Entities::Error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
add_swagger_documentation
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def app
|
48
|
+
MyAPI::ResponseModelApi
|
49
|
+
end
|
50
|
+
|
51
|
+
subject do
|
52
|
+
get '/swagger_doc/something'
|
53
|
+
JSON.parse(last_response.body)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should document specified models' do
|
57
|
+
expect(subject['apis'][0]['operations'][0]['responseMessages']).to eq(
|
58
|
+
[
|
59
|
+
{
|
60
|
+
'code' => 200,
|
61
|
+
'message' => 'OK',
|
62
|
+
'responseModel' => 'Something'
|
63
|
+
},
|
64
|
+
{
|
65
|
+
'code' => 403,
|
66
|
+
'message' => 'Refused to return something',
|
67
|
+
'responseModel' => 'Error'
|
68
|
+
}
|
69
|
+
]
|
70
|
+
)
|
71
|
+
expect(subject['models'].keys).to include 'Error'
|
72
|
+
expect(subject['models']['Error']).to eq(
|
73
|
+
'id' => 'Error',
|
74
|
+
'properties' => {
|
75
|
+
'code' => { 'type' => 'string', 'description' => 'Error code' },
|
76
|
+
'message' => { 'type' => 'string', 'description' => 'Error message' }
|
77
|
+
}
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
@@ -1,58 +1,56 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe 'a simple mounted api' do
|
4
4
|
before :all do
|
5
5
|
class CustomType; end
|
6
6
|
|
7
7
|
class SimpleMountedApi < Grape::API
|
8
|
-
desc
|
8
|
+
desc 'Document root'
|
9
9
|
get do
|
10
10
|
end
|
11
11
|
|
12
|
-
desc 'This gets something.',
|
13
|
-
|
14
|
-
}
|
12
|
+
desc 'This gets something.',
|
13
|
+
notes: '_test_'
|
15
14
|
|
16
15
|
get '/simple' do
|
17
16
|
{ bla: 'something' }
|
18
17
|
end
|
19
18
|
|
20
|
-
desc 'This gets something for URL using - separator.',
|
21
|
-
|
22
|
-
}
|
19
|
+
desc 'This gets something for URL using - separator.',
|
20
|
+
notes: '_test_'
|
23
21
|
|
24
22
|
get '/simple-test' do
|
25
23
|
{ bla: 'something' }
|
26
24
|
end
|
27
25
|
|
28
|
-
desc 'this gets something else',
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
desc 'this gets something else',
|
27
|
+
headers: {
|
28
|
+
'XAuthToken' => { description: 'A required header.', required: true },
|
29
|
+
'XOtherHeader' => { description: 'An optional header.', required: false }
|
30
|
+
},
|
31
|
+
http_codes: {
|
32
|
+
403 => 'invalid pony',
|
33
|
+
405 => 'no ponies left!'
|
34
|
+
}
|
35
|
+
|
38
36
|
get '/simple_with_headers' do
|
39
|
-
{:
|
37
|
+
{ bla: 'something_else' }
|
40
38
|
end
|
41
39
|
|
42
|
-
desc 'this takes an array of parameters',
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
desc 'this takes an array of parameters',
|
41
|
+
params: {
|
42
|
+
'items[]' => { description: 'array of items' }
|
43
|
+
}
|
44
|
+
|
47
45
|
post '/items' do
|
48
46
|
{}
|
49
47
|
end
|
50
48
|
|
51
|
-
desc 'this uses a custom parameter',
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
desc 'this uses a custom parameter',
|
50
|
+
params: {
|
51
|
+
'custom' => { type: CustomType, description: 'array of items' }
|
52
|
+
}
|
53
|
+
|
56
54
|
get '/custom' do
|
57
55
|
{}
|
58
56
|
end
|
@@ -64,126 +62,123 @@ describe "a simple mounted api" do
|
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
|
-
def app
|
65
|
+
def app
|
66
|
+
SimpleApi
|
67
|
+
end
|
68
68
|
|
69
|
-
it
|
69
|
+
it 'retrieves swagger-documentation on /swagger_doc' do
|
70
70
|
get '/swagger_doc.json'
|
71
|
-
JSON.parse(last_response.body).
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
{
|
80
|
-
{
|
81
|
-
{
|
82
|
-
{
|
83
|
-
{ "path" => "/swagger_doc/custom.{format}" },
|
84
|
-
{ "path" => "/swagger_doc/swagger_doc.{format}" }
|
71
|
+
expect(JSON.parse(last_response.body)).to eq(
|
72
|
+
'apiVersion' => '0.1',
|
73
|
+
'swaggerVersion' => '1.2',
|
74
|
+
'info' => {},
|
75
|
+
'produces' => ['application/xml', 'application/json', 'application/vnd.api+json', 'text/plain'],
|
76
|
+
'apis' => [
|
77
|
+
{ 'path' => '/simple.{format}', 'description' => 'Operations about simples' },
|
78
|
+
{ 'path' => '/simple-test.{format}', 'description' => 'Operations about simple-tests' },
|
79
|
+
{ 'path' => '/simple_with_headers.{format}', 'description' => 'Operations about simple_with_headers' },
|
80
|
+
{ 'path' => '/items.{format}', 'description' => 'Operations about items' },
|
81
|
+
{ 'path' => '/custom.{format}', 'description' => 'Operations about customs' },
|
82
|
+
{ 'path' => '/swagger_doc.{format}', 'description' => 'Operations about swagger_docs' }
|
85
83
|
]
|
86
|
-
|
84
|
+
)
|
87
85
|
end
|
88
86
|
|
89
|
-
it
|
87
|
+
it 'retrieves the documentation for mounted-api' do
|
90
88
|
get '/swagger_doc/simple.json'
|
91
|
-
JSON.parse(last_response.body).
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
89
|
+
expect(JSON.parse(last_response.body)).to eq(
|
90
|
+
'apiVersion' => '0.1',
|
91
|
+
'swaggerVersion' => '1.2',
|
92
|
+
'basePath' => 'http://example.org',
|
93
|
+
'resourcePath' => '/simple',
|
94
|
+
'produces' => ['application/xml', 'application/json', 'application/vnd.api+json', 'text/plain'],
|
95
|
+
'apis' => [{
|
96
|
+
'path' => '/simple.{format}',
|
97
|
+
'operations' => [{
|
98
|
+
'notes' => '_test_',
|
99
|
+
'summary' => 'This gets something.',
|
100
|
+
'nickname' => 'GET-simple---format-',
|
101
|
+
'method' => 'GET',
|
102
|
+
'parameters' => [],
|
103
|
+
'type' => 'void'
|
105
104
|
}]
|
106
105
|
}]
|
107
|
-
|
106
|
+
)
|
108
107
|
end
|
109
108
|
|
110
|
-
context
|
109
|
+
context 'retrieves the documentation for mounted-api that' do
|
111
110
|
it "contains '-' in URL" do
|
112
111
|
get '/swagger_doc/simple-test.json'
|
113
|
-
JSON.parse(last_response.body).
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
112
|
+
expect(JSON.parse(last_response.body)).to eq(
|
113
|
+
'apiVersion' => '0.1',
|
114
|
+
'swaggerVersion' => '1.2',
|
115
|
+
'basePath' => 'http://example.org',
|
116
|
+
'resourcePath' => '/simple-test',
|
117
|
+
'produces' => ['application/xml', 'application/json', 'application/vnd.api+json', 'text/plain'],
|
118
|
+
'apis' => [{
|
119
|
+
'path' => '/simple-test.{format}',
|
120
|
+
'operations' => [{
|
121
|
+
'notes' => '_test_',
|
122
|
+
'summary' => 'This gets something for URL using - separator.',
|
123
|
+
'nickname' => 'GET-simple-test---format-',
|
124
|
+
'method' => 'GET',
|
125
|
+
'parameters' => [],
|
126
|
+
'type' => 'void'
|
127
127
|
}]
|
128
128
|
}]
|
129
|
-
|
129
|
+
)
|
130
130
|
end
|
131
131
|
|
132
|
-
it
|
132
|
+
it 'includes headers' do
|
133
133
|
get '/swagger_doc/simple_with_headers.json'
|
134
|
-
JSON.parse(last_response.body)[
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
{ "paramType" => "header", "name" => "XAuthToken", "description" => "A required header.", "type" => "String", "dataType" => "String", "required" => true },
|
145
|
-
{ "paramType" => "header", "name" => "XOtherHeader", "description" => "An optional header.", "type" => "String", "dataType" => "String", "required" => false }
|
134
|
+
expect(JSON.parse(last_response.body)['apis']).to eq [{
|
135
|
+
'path' => '/simple_with_headers.{format}',
|
136
|
+
'operations' => [{
|
137
|
+
'notes' => '',
|
138
|
+
'summary' => 'this gets something else',
|
139
|
+
'nickname' => 'GET-simple_with_headers---format-',
|
140
|
+
'method' => 'GET',
|
141
|
+
'parameters' => [
|
142
|
+
{ 'paramType' => 'header', 'name' => 'XAuthToken', 'description' => 'A required header.', 'type' => 'String', 'required' => true },
|
143
|
+
{ 'paramType' => 'header', 'name' => 'XOtherHeader', 'description' => 'An optional header.', 'type' => 'String', 'required' => false }
|
146
144
|
],
|
147
|
-
|
148
|
-
|
149
|
-
{
|
145
|
+
'type' => 'void',
|
146
|
+
'responseMessages' => [
|
147
|
+
{ 'code' => 403, 'message' => 'invalid pony' },
|
148
|
+
{ 'code' => 405, 'message' => 'no ponies left!' }
|
150
149
|
]
|
151
150
|
}]
|
152
151
|
}]
|
153
152
|
end
|
154
153
|
|
155
|
-
it
|
154
|
+
it 'supports multiple parameters' do
|
156
155
|
get '/swagger_doc/items.json'
|
157
|
-
JSON.parse(last_response.body)[
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
"parameters" => [ { "paramType" => "form", "name" => "items[]", "description" => "array of items", "type" => "String", "dataType" => "String", "required" => false } ]
|
156
|
+
expect(JSON.parse(last_response.body)['apis']).to eq [{
|
157
|
+
'path' => '/items.{format}',
|
158
|
+
'operations' => [{
|
159
|
+
'notes' => '',
|
160
|
+
'summary' => 'this takes an array of parameters',
|
161
|
+
'nickname' => 'POST-items---format-',
|
162
|
+
'method' => 'POST',
|
163
|
+
'parameters' => [{ 'paramType' => 'form', 'name' => 'items[]', 'description' => 'array of items', 'type' => 'string', 'required' => false, 'allowMultiple' => false }],
|
164
|
+
'type' => 'void'
|
167
165
|
}]
|
168
166
|
}]
|
169
167
|
end
|
170
168
|
|
171
|
-
it
|
169
|
+
it 'supports custom types' do
|
172
170
|
get '/swagger_doc/custom.json'
|
173
|
-
JSON.parse(last_response.body)[
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
"parameters" => [ { "paramType" => "query", "name" => "custom", "description" => "array of items", "type" => "CustomType", "dataType" => "CustomType", "required" => false } ]
|
171
|
+
expect(JSON.parse(last_response.body)['apis']).to eq [{
|
172
|
+
'path' => '/custom.{format}',
|
173
|
+
'operations' => [{
|
174
|
+
'notes' => '',
|
175
|
+
'summary' => 'this uses a custom parameter',
|
176
|
+
'nickname' => 'GET-custom---format-',
|
177
|
+
'method' => 'GET',
|
178
|
+
'parameters' => [{ 'paramType' => 'query', 'name' => 'custom', 'description' => 'array of items', 'type' => 'CustomType', 'required' => false, 'allowMultiple' => false }],
|
179
|
+
'type' => 'void'
|
183
180
|
}]
|
184
181
|
}]
|
185
182
|
end
|
186
|
-
|
187
183
|
end
|
188
|
-
|
189
184
|
end
|
data/spec/spec_helper.rb
CHANGED
data/test/api.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'grape'
|
2
|
+
require '../lib/grape-swagger'
|
3
|
+
|
4
|
+
@@splines = {}
|
5
|
+
|
6
|
+
class Api < Grape::API
|
7
|
+
format :json
|
8
|
+
|
9
|
+
desc 'API Root'
|
10
|
+
get do
|
11
|
+
{ splines_url: '/splines' }
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :splines do
|
15
|
+
desc 'Return a spline.'
|
16
|
+
params do
|
17
|
+
requires :id, type: Integer, desc: 'Spline id.'
|
18
|
+
end
|
19
|
+
get ':id' do
|
20
|
+
@@splines[params[:id]] || error!('Not Found', 404)
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Update a spline.'
|
24
|
+
params do
|
25
|
+
requires :id, type: Integer, desc: 'Spline id.'
|
26
|
+
optional :reticulated, type: Boolean, default: true, desc: 'True if the spline is reticulated.'
|
27
|
+
end
|
28
|
+
put ':id' do
|
29
|
+
spline = (@@splines[params[:id]] || error!('Not Found', 404))
|
30
|
+
spline[:reticulated] = params[:reticulated]
|
31
|
+
spline
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Create a spline.'
|
35
|
+
params do
|
36
|
+
optional :reticulated, type: Boolean, default: true, desc: 'True if the spline is reticulated.'
|
37
|
+
end
|
38
|
+
post do
|
39
|
+
spline = { id: @@splines.size + 1, reticulated: params[:reticulated] }
|
40
|
+
@@splines[@@splines.size + 1] = spline
|
41
|
+
spline
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Return all splines.'
|
45
|
+
get do
|
46
|
+
@@splines.values
|
47
|
+
end
|
48
|
+
|
49
|
+
# TEST api for testing uploading
|
50
|
+
# curl --form file=@splines.png http://localhost:9292/splines/upload
|
51
|
+
desc 'Update image'
|
52
|
+
post 'upload' do
|
53
|
+
filename = params[:file][:filename]
|
54
|
+
content_type 'application/octet-stream'
|
55
|
+
env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
|
56
|
+
header 'Content-Disposition', "attachment; filename*=UTF-8''#{URI.escape(filename)}"
|
57
|
+
params[:file][:tempfile].read
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
add_swagger_documentation
|
62
|
+
end
|