grape-swagger 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rubocop.yml +36 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +3 -0
  7. data/CHANGELOG.md +90 -0
  8. data/CONTRIBUTING.md +126 -0
  9. data/Gemfile +1 -21
  10. data/LICENSE.txt +1 -1
  11. data/README.md +397 -0
  12. data/RELEASING.md +80 -0
  13. data/Rakefile +6 -23
  14. data/UPGRADING.md +47 -0
  15. data/grape-swagger.gemspec +26 -84
  16. data/lib/grape-swagger.rb +237 -111
  17. data/lib/grape-swagger/errors.rb +9 -0
  18. data/lib/grape-swagger/markdown.rb +23 -0
  19. data/lib/grape-swagger/markdown/kramdown_adapter.rb +37 -0
  20. data/lib/grape-swagger/markdown/redcarpet_adapter.rb +89 -0
  21. data/lib/grape-swagger/version.rb +3 -0
  22. data/spec/api_description_spec.rb +41 -0
  23. data/spec/api_global_models_spec.rb +76 -0
  24. data/spec/api_models_spec.rb +190 -93
  25. data/spec/default_api_spec.rb +31 -36
  26. data/spec/form_params_spec.rb +56 -53
  27. data/spec/grape-swagger_helper_spec.rb +88 -49
  28. data/spec/grape-swagger_spec.rb +7 -5
  29. data/spec/hide_api_spec.rb +58 -55
  30. data/spec/markdown/kramdown_adapter_spec.rb +38 -0
  31. data/spec/markdown/markdown_spec.rb +27 -0
  32. data/spec/markdown/redcarpet_adapter_spec.rb +81 -0
  33. data/spec/namespaced_api_spec.rb +47 -0
  34. data/spec/non_default_api_spec.rb +372 -222
  35. data/spec/response_model_spec.rb +80 -0
  36. data/spec/simple_mounted_api_spec.rb +113 -118
  37. data/spec/spec_helper.rb +0 -1
  38. data/spec/version_spec.rb +8 -0
  39. data/test/api.rb +62 -0
  40. data/test/config.ru +10 -2
  41. data/test/splines.png +0 -0
  42. metadata +145 -91
  43. data/.rvmrc +0 -48
  44. data/CHANGELOG.markdown +0 -55
  45. data/Gemfile.lock +0 -94
  46. data/README.markdown +0 -168
  47. data/VERSION +0 -1
  48. 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 "a simple mounted api" do
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 "Document root"
8
+ desc 'Document root'
9
9
  get do
10
10
  end
11
11
 
12
- desc 'This gets something.', {
13
- :notes => '_test_'
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
- :notes => '_test_'
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
- :headers => {
30
- "XAuthToken" => { description: "A required header.", required: true },
31
- "XOtherHeader" => { description: "An optional header.", required: false }
32
- },
33
- :http_codes => {
34
- 403 => "invalid pony",
35
- 405 => "no ponies left!"
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
- {:bla => 'something_else'}
37
+ { bla: 'something_else' }
40
38
  end
41
39
 
42
- desc 'this takes an array of parameters', {
43
- :params => {
44
- "items[]" => { description: "array of items" }
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
- :params => {
53
- "custom" => { type: CustomType, description: "array of items" }
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; SimpleApi end
65
+ def app
66
+ SimpleApi
67
+ end
68
68
 
69
- it "retrieves swagger-documentation on /swagger_doc" do
69
+ it 'retrieves swagger-documentation on /swagger_doc' do
70
70
  get '/swagger_doc.json'
71
- JSON.parse(last_response.body).should == {
72
- "apiVersion" => "0.1",
73
- "swaggerVersion" => "1.2",
74
- "basePath" => "http://example.org",
75
- "info" => {},
76
- "produces" => ["application/xml", "application/json", "text/plain"],
77
- "operations" => [],
78
- "apis" => [
79
- { "path" => "/swagger_doc/simple.{format}" },
80
- { "path" => "/swagger_doc/simple-test.{format}" },
81
- { "path" => "/swagger_doc/simple_with_headers.{format}" },
82
- { "path" => "/swagger_doc/items.{format}" },
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 "retrieves the documentation for mounted-api" do
87
+ it 'retrieves the documentation for mounted-api' do
90
88
  get '/swagger_doc/simple.json'
91
- JSON.parse(last_response.body).should == {
92
- "apiVersion" => "0.1",
93
- "swaggerVersion" => "1.2",
94
- "basePath" => "http://example.org",
95
- "resourcePath" => "",
96
- "apis" => [{
97
- "path" => "/simple.{format}",
98
- "operations" => [{
99
- "produces" => ["application/xml", "application/json", "text/plain"],
100
- "notes" => "_test_",
101
- "summary" => "This gets something.",
102
- "nickname" => "GET-simple---format-",
103
- "httpMethod" => "GET",
104
- "parameters" => []
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 "retrieves the documentation for mounted-api that" do
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).should == {
114
- "apiVersion" => "0.1",
115
- "swaggerVersion" => "1.2",
116
- "basePath" => "http://example.org",
117
- "resourcePath" => "",
118
- "apis" => [{
119
- "path" => "/simple-test.{format}",
120
- "operations" => [{
121
- "produces" => ["application/xml", "application/json", "text/plain"],
122
- "notes" => "_test_",
123
- "summary" => "This gets something for URL using - separator.",
124
- "nickname" => "GET-simple-test---format-",
125
- "httpMethod" => "GET",
126
- "parameters" => []
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 "includes headers" do
132
+ it 'includes headers' do
133
133
  get '/swagger_doc/simple_with_headers.json'
134
- JSON.parse(last_response.body)["apis"].should == [{
135
- "path" => "/simple_with_headers.{format}",
136
- "operations" => [{
137
- "produces" => ["application/xml", "application/json", "text/plain"],
138
- "notes" => nil,
139
- "notes" => "",
140
- "summary" => "this gets something else",
141
- "nickname" => "GET-simple_with_headers---format-",
142
- "httpMethod" => "GET",
143
- "parameters" => [
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
- "responseMessages" => [
148
- { "code" => 403, "message" => "invalid pony" },
149
- { "code" => 405, "message" => "no ponies left!" }
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 "supports multiple parameters" do
154
+ it 'supports multiple parameters' do
156
155
  get '/swagger_doc/items.json'
157
- JSON.parse(last_response.body)["apis"].should == [{
158
- "path" => "/items.{format}",
159
- "operations" => [{
160
- "produces" => ["application/xml", "application/json", "text/plain"],
161
- "notes" => nil,
162
- "notes" => "",
163
- "summary" => "this takes an array of parameters",
164
- "nickname" => "POST-items---format-",
165
- "httpMethod" => "POST",
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 "supports custom types" do
169
+ it 'supports custom types' do
172
170
  get '/swagger_doc/custom.json'
173
- JSON.parse(last_response.body)["apis"].should == [{
174
- "path" => "/custom.{format}",
175
- "operations" => [{
176
- "produces" => ["application/xml", "application/json", "text/plain"],
177
- "notes" => nil,
178
- "notes" => "",
179
- "summary" => "this uses a custom parameter",
180
- "nickname" => "GET-custom---format-",
181
- "httpMethod" => "GET",
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
@@ -9,7 +9,6 @@ require 'grape-entity'
9
9
  require 'rubygems'
10
10
  require 'bundler'
11
11
 
12
- require 'pry'
13
12
  require 'json'
14
13
 
15
14
  Bundler.setup :default, :test
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe GrapeSwagger do
4
+ it '#version' do
5
+ expect(GrapeSwagger::VERSION).to_not be_nil
6
+ expect(GrapeSwagger::VERSION.split('.').count).to eq 3
7
+ end
8
+ end
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