swaggable 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Swaggable
2
+ VERSION = '0.4.0'
3
+ end
@@ -0,0 +1 @@
1
+ {"swagger":"2.0","info":{"description":"This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.","version":"1.0.0","title":"Swagger Petstore","termsOfService":"http://swagger.io/terms/","contact":{"email":"apiteam@swagger.io"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"}},"host":"petstore.swagger.io","basePath":"/v2","tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders"},{"name":"user","description":"Operations about user","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}}],"schemes":["http"],"paths":{"/pet":{"post":{"tags":["pet"],"summary":"Add a new pet to the store","description":"","operationId":"addPet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"put":{"tags":["pet"],"summary":"Update an existing pet","description":"","operationId":"updatePet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma seperated strings","operationId":"findPetsByStatus","produces":["application/xml","application/json"],"parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":true,"type":"array","items":{"type":"string","enum":["available","pending","sold"],"default":"available"},"collectionFormat":"csv"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","produces":["application/xml","application/json"],"parameters":[{"name":"tags","in":"query","description":"Tags to filter by","required":true,"type":"array","items":{"type":"string"},"collectionFormat":"csv"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Pet"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","description":"","operationId":"updatePetWithForm","consumes":["application/x-www-form-urlencoded"],"produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"type":"integer","format":"int64"},{"name":"name","in":"formData","description":"Updated name of the pet","required":false,"type":"string"},{"name":"status","in":"formData","description":"Updated status of the pet","required":false,"type":"string"}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","produces":["application/xml","application/json"],"parameters":[{"name":"api_key","in":"header","required":false,"type":"string"},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"type":"integer","format":"int64"}],"responses":{"400":{"description":"Invalid pet value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","consumes":["multipart/form-data"],"produces":["application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"type":"integer","format":"int64"},{"name":"additionalMetadata","in":"formData","description":"Additional data to pass to server","required":false,"type":"string"},{"name":"file","in":"formData","description":"file to upload","required":false,"type":"file"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/ApiResponse"}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","produces":["application/json"],"parameters":[],"responses":{"200":{"description":"successful operation","schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"security":[{"api_key":[]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"","operationId":"placeOrder","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"order placed for purchasing the pet","required":true,"schema":{"$ref":"#/definitions/Order"}}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid Order"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions","operationId":"getOrderById","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of pet that needs to be fetched","required":true,"type":"integer","maximum":5.0,"minimum":1.0,"format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors","operationId":"deleteOrder","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"type":"string","minimum":1.0}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","operationId":"createUser","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Created user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithArray":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithArrayInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithListInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"query","description":"The user name for login","required":true,"type":"string"},{"name":"password","in":"query","description":"The password for login in clear text","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"type":"string"},"headers":{"X-Rate-Limit":{"type":"integer","format":"int32","description":"calls per hour allowed by the user"},"X-Expires-After":{"type":"string","format":"date-time","description":"date in UTC when toekn expires"}}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged in user session","description":"","operationId":"logoutUser","produces":["application/xml","application/json"],"parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/User"}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Updated user","description":"This can only be done by the logged in user.","operationId":"updateUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"name that need to be deleted","required":true,"type":"string"},{"in":"body","name":"body","description":"Updated user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"400":{"description":"Invalid user supplied"},"404":{"description":"User not found"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"type":"string"}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}}},"securityDefinitions":{"petstore_auth":{"type":"oauth2","authorizationUrl":"http://petstore.swagger.io/api/oauth/dialog","flow":"implicit","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}},"api_key":{"type":"apiKey","name":"api_key","in":"header"}},"definitions":{"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"petId":{"type":"integer","format":"int64"},"quantity":{"type":"integer","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean","default":false}},"xml":{"name":"Order"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Category"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"integer","format":"int32","description":"User Status"}},"xml":{"name":"User"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Tag"}},"Pet":{"type":"object","required":["name","photoUrls"],"properties":{"id":{"type":"integer","format":"int64"},"category":{"$ref":"#/definitions/Category"},"name":{"type":"string","example":"doggie"},"photoUrls":{"type":"array","xml":{"name":"photoUrl","wrapped":true},"items":{"type":"string"}},"tags":{"type":"array","xml":{"name":"tag","wrapped":true},"items":{"$ref":"#/definitions/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"Pet"}},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}}}},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"}}
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'pry'
4
+ require 'webmock/rspec'
5
+
6
+ RSpec.configure do |config|
7
+ config.color = true
8
+ config.tty = true
9
+ config.disable_monkey_patching!
10
+ # config.full_backtrace = true
11
+ # config.formatter = :documentation # :documentation, :progress, :html, :textmate
12
+ end
13
+
14
+ $LOAD_PATH.unshift File.expand_path('lib')
15
+ require 'swaggable'
16
+
17
+ $LOAD_PATH.unshift File.expand_path('spec/support')
18
+
@@ -0,0 +1,169 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe 'Swaggable::ApiDefinition' do
4
+ let(:subject_class) { Swaggable::ApiDefinition }
5
+ let(:subject_instance) { Swaggable::ApiDefinition.new }
6
+ subject { subject_instance }
7
+
8
+ it 'has a version' do
9
+ subject.version = 'v2.0'
10
+ expect(subject.version).to eq 'v2.0'
11
+ end
12
+
13
+ it 'has a title' do
14
+ subject.title = 'a new title'
15
+ expect(subject.title).to eq 'a new title'
16
+ end
17
+
18
+ it 'has a description' do
19
+ subject.description = 'a new description'
20
+ expect(subject.description).to eq 'a new description'
21
+ end
22
+
23
+ it 'has a base_path' do
24
+ subject.base_path = 'a new base_path'
25
+ expect(subject.base_path).to eq 'a new base_path'
26
+ end
27
+
28
+ it 'has endpoints' do
29
+ endpoint = Swaggable::EndpointDefinition.new verb: :get, path: '/'
30
+ subject.endpoints << endpoint
31
+ expect(subject.endpoints.first).to eq endpoint
32
+ end
33
+
34
+ describe '#endpoints' do
35
+ subject { subject_instance.endpoints }
36
+
37
+ it 'accumulates endpoints with <<' do
38
+ endpoint = Swaggable::EndpointDefinition.new verb: :get, path: '/'
39
+ subject << endpoint
40
+ expect(subject['GET /']).to be endpoint
41
+ end
42
+
43
+ it 'accumulates endpoints with add' do
44
+ endpoint = Swaggable::EndpointDefinition.new verb: :get, path: '/'
45
+ subject.add endpoint
46
+ expect(subject['GET /']).to be endpoint
47
+ end
48
+
49
+ it 'adds new endpoints' do
50
+ endpoint = subject.add_new do |e|
51
+ e.verb = :post
52
+ e.path = '/users'
53
+ end
54
+
55
+ expect(subject['POST /users']).to be endpoint
56
+ end
57
+
58
+ it 'iterates through endpoints' do
59
+ has_run = false
60
+
61
+ endpoint = subject.add_new do |e|
62
+ e.verb = :post
63
+ e.path = '/users'
64
+ end
65
+
66
+ subject.each do |e|
67
+ has_run = true
68
+ expect(e).to be endpoint
69
+ end
70
+ end
71
+
72
+ it 'converts to array' do
73
+ endpoint = subject.add_new do |e|
74
+ e.verb = :post
75
+ e.path = '/users'
76
+ end
77
+
78
+ expect(subject.to_a).to eq [endpoint]
79
+ end
80
+
81
+ it 'clears' do
82
+ endpoint = subject.add_new do |e|
83
+ e.verb = :post
84
+ e.path = '/users'
85
+ end
86
+
87
+ subject.clear
88
+
89
+ expect(subject.to_a).to eq []
90
+ end
91
+ end
92
+
93
+ describe '#tags' do
94
+ it 'is collected from endpoints' do
95
+ tag = instance_double(Swaggable::TagDefinition, name: 'A tag')
96
+ endpoint = Swaggable::EndpointDefinition.new verb: :get, path: '/'
97
+ endpoint.tags << tag
98
+ subject.endpoints << endpoint
99
+ expect(subject.tags.first).to eq tag
100
+ end
101
+
102
+ it 'avoids duplicates' do
103
+ tag_1 = Swaggable::TagDefinition.new name: 'tag_1'
104
+ tag_1_again = Swaggable::TagDefinition.new name: 'tag_1'
105
+ tag_2 = Swaggable::TagDefinition.new name: 'tag_2'
106
+
107
+ endpoint_a = Swaggable::EndpointDefinition.new
108
+ endpoint_b = Swaggable::EndpointDefinition.new
109
+
110
+ endpoint_a.tags << tag_1
111
+ endpoint_b.tags << tag_1_again
112
+ endpoint_b.tags << tag_2
113
+
114
+ subject.endpoints << endpoint_a
115
+ subject.endpoints << endpoint_b
116
+
117
+ expect(subject.tags.to_a).to eq [tag_1_again, tag_2]
118
+ end
119
+
120
+ it 'is empty array when no tags are present' do
121
+ subject.endpoints.clear
122
+ expect(subject.tags).to eq []
123
+ end
124
+
125
+ it 'is frozen to avoid giving the false impression that it can be modified' do
126
+ expect{ subject.tags << instance_double(Swaggable::TagDefinition) }.to raise_error
127
+ end
128
+ end
129
+
130
+ it 'yields itself on initialize' do
131
+ yielded = false
132
+
133
+ subject_class.new do |s|
134
+ expect(s).to be_a subject_class
135
+ yielded = true
136
+ end
137
+
138
+ expect(yielded).to be true
139
+ end
140
+
141
+ it 'builds from a Grape API' do
142
+ allow(subject_class.grape_adapter).to receive(:import) { |grape, api| api.title = 'A test'; api }
143
+ result = subject_class.from_grape_api double('grape')
144
+ expect(result.title).to eq 'A test'
145
+ end
146
+
147
+ it 'has a dsl' do
148
+ api = Swaggable::ApiDefinition.new
149
+
150
+ api.configure do
151
+ version 'v1.0'
152
+ title 'My API'
153
+ description 'My cool API'
154
+ base_path '/a/path'
155
+
156
+ endpoints do
157
+ add_new do
158
+ path '/users'
159
+ verb :post
160
+ description 'Creates users'
161
+ summary 'Allows to create an user'
162
+ end
163
+ end
164
+ end
165
+
166
+ expect(api.version).to eq 'v1.0'
167
+ expect(api.endpoints.first.path).to eq '/users'
168
+ end
169
+ end
@@ -0,0 +1,77 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe 'Swaggable::EndpointDefinition' do
4
+ let(:subject_class) { Swaggable::EndpointDefinition }
5
+ let(:subject_instance) { Swaggable::EndpointDefinition.new }
6
+ subject { subject_instance }
7
+
8
+ it 'has a path' do
9
+ subject.path = '/'
10
+ expect(subject.path).to eq '/'
11
+ end
12
+
13
+ it 'has a verb' do
14
+ subject.verb = 'POST'
15
+ expect(subject.verb).to eq 'POST'
16
+ end
17
+
18
+ it 'has a description' do
19
+ subject.description = 'a new desc'
20
+ expect(subject.description).to eq 'a new desc'
21
+ end
22
+
23
+ it 'has a summary' do
24
+ subject.summary = 'a new summary'
25
+ expect(subject.summary).to eq 'a new summary'
26
+ end
27
+
28
+ it 'has tags' do
29
+ tag = instance_double(Swaggable::TagDefinition, name: 'A Tag')
30
+ subject.tags << tag
31
+ expect(subject.tags.to_a).to eq [tag]
32
+ end
33
+
34
+ it 'has consumes' do
35
+ format = double('format')
36
+ subject.consumes << format
37
+ expect(subject.consumes).to eq [format]
38
+ end
39
+
40
+ it 'has produces' do
41
+ format = double('format')
42
+ subject.produces << format
43
+ expect(subject.produces).to eq [format]
44
+ end
45
+
46
+ it 'has parameters' do
47
+ parameter = Swaggable::ParameterDefinition.new name: 'some_parameter'
48
+ subject.parameters << parameter
49
+ expect(subject.parameters.to_a).to eq [parameter]
50
+ end
51
+
52
+ it 'yields itself on initialize' do
53
+ yielded = false
54
+
55
+ subject_class.new do |s|
56
+ expect(s).to be_a subject_class
57
+ yielded = true
58
+ end
59
+
60
+ expect(yielded).to be true
61
+ end
62
+
63
+ it 'accepts attributes on initialize' do
64
+ endpoint = subject_class.new path: '/a/path', verb: 'GET'
65
+ expect(endpoint.path).to eq '/a/path'
66
+ expect(endpoint.verb).to eq 'GET'
67
+ end
68
+
69
+ it 'has responses' do
70
+ subject.responses.add_new do
71
+ status 418
72
+ description 'Teapot'
73
+ end
74
+
75
+ expect(subject.responses[418].description).to eq 'Teapot'
76
+ end
77
+ end
@@ -0,0 +1,198 @@
1
+ require_relative '../spec_helper'
2
+ require 'grape'
3
+
4
+ RSpec.describe 'Swaggable::GrapeAdapter' do
5
+ let(:subject_class) { Swaggable::GrapeAdapter }
6
+ let(:subject_instance) { Swaggable::GrapeAdapter.new }
7
+ subject { subject_instance }
8
+
9
+ describe '#import(grape_api, api_definition)' do
10
+ let(:api) { Swaggable::ApiDefinition.new }
11
+ let(:grape) { Class.new(Grape::API) }
12
+
13
+ def do_import
14
+ subject.import grape, api
15
+ end
16
+
17
+ it 'returns the api' do
18
+ api = do_import
19
+ expect(api).to be_a Swaggable::ApiDefinition
20
+ end
21
+
22
+ it 'sets version' do
23
+ grape.version 'v2.0'
24
+ do_import
25
+ expect(api.version).to eq 'v2.0'
26
+ end
27
+
28
+ it 'sets title' do
29
+ allow(grape).to receive(:name).and_return('MyAPI')
30
+ do_import
31
+ expect(api.title).to eq 'MyAPI'
32
+ end
33
+
34
+ it 'sets base path' do
35
+ do_import
36
+ expect(api.base_path).to eq '/'
37
+ end
38
+
39
+ describe 'endpoints' do
40
+ it 'sets verb' do
41
+ grape.post { }
42
+ do_import
43
+ expect(api.endpoints.first.verb).to eq 'post'
44
+ end
45
+
46
+ it 'sets description as summary' do
47
+ grape.desc 'My endpoint'
48
+ grape.post { }
49
+ do_import
50
+ expect(api.endpoints.first.summary).to eq 'My endpoint'
51
+ end
52
+
53
+ it 'sets format' do
54
+ grape.format :json
55
+ grape.post { }
56
+ do_import
57
+ expect(api.endpoints.first.produces).to eq ['application/json']
58
+ end
59
+
60
+ describe 'path' do
61
+ it 'has no (.:format)' do
62
+ grape.post('/a/path') { }
63
+ do_import
64
+ expect(api.endpoints.first.path).to eq '/a/path'
65
+ end
66
+
67
+ it 'has no (/.:format)' do
68
+ grape.version 'v1.0'
69
+ grape.get('/') { }
70
+ do_import
71
+ expect(api.endpoints.first.path).to eq '/v1.0'
72
+ end
73
+
74
+ it 'has version number' do
75
+ grape.version 'v3.0'
76
+ grape.post('/a/path') { }
77
+ do_import
78
+ expect(api.endpoints.first.path).to eq '/v3.0/a/path'
79
+ end
80
+
81
+ it 'has version number if present with prefix too' do
82
+ grape.version 'v3.0'
83
+ grape.prefix '/api'
84
+ grape.post('/a/path') { }
85
+ do_import
86
+ expect(api.endpoints.first.path).to eq '/api/v3.0/a/path'
87
+ end
88
+
89
+ it 'has version number if present with prefix not beginning with / too' do
90
+ grape.version 'v3.0'
91
+ grape.prefix 'api'
92
+ grape.post('/a/path') { }
93
+ do_import
94
+ expect(api.endpoints.first.path).to eq '/api/v3.0/a/path'
95
+ end
96
+
97
+ it 'has parameters' do
98
+ grape.version 'v3.0'
99
+ grape.prefix '/api'
100
+ grape.post('/a/path/:with/:parameters') { }
101
+ do_import
102
+ expect(api.endpoints.first.path).to eq '/api/v3.0/a/path/{with}/{parameters}'
103
+ end
104
+
105
+ it 'has tags' do
106
+ grape.post('/a/path') { }
107
+ do_import
108
+ tag = api.endpoints.first.tags.first
109
+ expect(tag.name).to eq grape.name
110
+ end
111
+ end
112
+
113
+ describe 'parameters' do
114
+ it 'have name' do
115
+ grape.params do
116
+ requires :user_uuid
117
+ end
118
+
119
+ grape.post('/a/path') { }
120
+
121
+ do_import
122
+ expect(api.endpoints.first.parameters.first.name).to eq 'user_uuid'
123
+ end
124
+
125
+ it 'have type' do
126
+ grape.params do
127
+ requires :user_uuid, type: String
128
+ end
129
+
130
+ grape.post('/a/path') { }
131
+
132
+ do_import
133
+ expect(api.endpoints.first.parameters.first.type).to eq :string
134
+ end
135
+
136
+ it 'have required' do
137
+ grape.params do
138
+ requires :required_param
139
+ end
140
+
141
+ grape.post('/a/path') { }
142
+
143
+ do_import
144
+ expect(api.endpoints.first.parameters.first.required).to eq true
145
+ end
146
+
147
+ it 'have description' do
148
+ grape.params do
149
+ requires :param, desc: 'A param'
150
+ end
151
+
152
+ grape.post('/a/path') { }
153
+
154
+ do_import
155
+ expect(api.endpoints.first.parameters.first.description).to eq 'A param'
156
+ end
157
+
158
+ it 'have location path if path param' do
159
+ grape.params do
160
+ requires :required_param
161
+ end
162
+
163
+ grape.post('/a/:required_param') { }
164
+
165
+ do_import
166
+ expect(api.endpoints.first.parameters.first.location).to eq :path
167
+ end
168
+
169
+ it 'have location query if non-path param' do
170
+ grape.params do
171
+ requires :required_param
172
+ end
173
+
174
+ grape.post('/a') { }
175
+
176
+ do_import
177
+ expect(api.endpoints.first.parameters.first.location).to eq :query
178
+ end
179
+ end
180
+
181
+ describe 'responses' do
182
+ it 'have status' do
183
+ grape.post('/', http_codes: [201, 'Created']) { }
184
+
185
+ do_import
186
+ expect(api.endpoints.first.responses.first.status).to eq 201
187
+ end
188
+
189
+ it 'have description' do
190
+ grape.post('/', http_codes: [[201, 'Created']]) { }
191
+
192
+ do_import
193
+ expect(api.endpoints.first.responses.first.description).to eq 'Created'
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end