apiculture 0.1.6 → 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/.gitignore +3 -5
- data/.travis.yml +2 -0
- data/CHANGELOG.md +3 -0
- data/apiculture.gemspec +19 -20
- data/gemfiles/Gemfile.rack-1.x +2 -3
- data/gemfiles/Gemfile.rack-2.x +2 -3
- data/lib/apiculture/app.rb +4 -4
- data/lib/apiculture/app_documentation.rb +4 -0
- data/lib/apiculture/openapi_documentation.rb +224 -0
- data/lib/apiculture/sinatra_instance_methods.rb +5 -5
- data/lib/apiculture/version.rb +1 -1
- data/lib/apiculture.rb +41 -40
- metadata +42 -45
- data/spec/apiculture/action_spec.rb +0 -45
- data/spec/apiculture/app_documentation_spec.rb +0 -126
- data/spec/apiculture/method_documentation_spec.rb +0 -102
- data/spec/apiculture_spec.rb +0 -461
- data/spec/spec_helper.rb +0 -15
@@ -1,102 +0,0 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
require_relative '../../lib/apiculture/method_documentation'
|
3
|
-
|
4
|
-
describe Apiculture::MethodDocumentation do
|
5
|
-
it 'generates HTML from an ActionDefinition with path, verb and both route and request params' do
|
6
|
-
definition = Apiculture::ActionDefinition.new
|
7
|
-
|
8
|
-
definition.description = "This action bakes pancakes"
|
9
|
-
definition.parameters << Apiculture::Parameter.new(:name, 'Pancake name', true, String, :to_s)
|
10
|
-
definition.parameters << Apiculture::Parameter.new(:thickness, 'Pancake **thick**ness', false, Float, :to_f)
|
11
|
-
definition.parameters << Apiculture::Parameter.new(:diameter, 'Pancake diameter', false, Integer, :to_i)
|
12
|
-
|
13
|
-
definition.route_parameters << Apiculture::RouteParameter.new(:pan_id, 'ID of the pancake frying pan')
|
14
|
-
definition.http_verb = 'get'
|
15
|
-
definition.path = '/pancake/:pan_id/bake'
|
16
|
-
definition.responses << Apiculture::PossibleResponse.new(200, "Pancake has been baked", {diameter: 10, unit: "cm"})
|
17
|
-
definition.responses << Apiculture::PossibleResponse.new(417, "Frying pan too cold", "ERR_NO_HEAT")
|
18
|
-
|
19
|
-
documenter = described_class.new(definition)
|
20
|
-
|
21
|
-
generated_html = documenter.to_html_fragment
|
22
|
-
generated_markdown = documenter.to_markdown
|
23
|
-
|
24
|
-
expect(generated_html).not_to include('<body>')
|
25
|
-
|
26
|
-
expect(generated_html).to include('<h2>GET /pancake/:pan_id/bake</h2>')
|
27
|
-
expect(generated_html).to include('<p>This action bakes pancakes</p>')
|
28
|
-
expect(generated_html).to include('<h3>URL parameters</h3>')
|
29
|
-
expect(generated_html).to include('ID of the pancake frying pan')
|
30
|
-
expect(generated_html).to include('<h3>Request parameters</h3>')
|
31
|
-
expect(generated_html).to include('<p>Pancake name</p>')
|
32
|
-
expect(generated_html).to include('<p>Pancake has been baked</p>')
|
33
|
-
expect(generated_html).to include('<p>Frying pan too cold</p>')
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'generates HTML from an ActionDefinition without route params' do
|
37
|
-
definition = Apiculture::ActionDefinition.new
|
38
|
-
|
39
|
-
definition.description = "This action bakes pancakes"
|
40
|
-
definition.parameters << Apiculture::Parameter.new(:name, 'Pancake name', true, String, :to_s)
|
41
|
-
definition.parameters << Apiculture::Parameter.new(:thickness, 'Pancake **thick**ness', false, Float, :to_f)
|
42
|
-
definition.parameters << Apiculture::Parameter.new(:diameter, 'Pancake diameter', false, Integer, :to_i)
|
43
|
-
|
44
|
-
definition.http_verb = 'get'
|
45
|
-
definition.path = '/pancake'
|
46
|
-
|
47
|
-
documenter = described_class.new(definition)
|
48
|
-
generated_html = documenter.to_html_fragment
|
49
|
-
|
50
|
-
expect(generated_html).not_to include('<h3>URL parameters</h3>')
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'generates HTML from an ActionDefinition without request params' do
|
54
|
-
definition = Apiculture::ActionDefinition.new
|
55
|
-
|
56
|
-
definition.description = "This action bakes pancakes"
|
57
|
-
|
58
|
-
definition.route_parameters << Apiculture::RouteParameter.new(:pan_id, 'ID of the pancake frying pan')
|
59
|
-
definition.http_verb = 'get'
|
60
|
-
definition.path = '/pancake/:pan_id/bake'
|
61
|
-
|
62
|
-
documenter = described_class.new(definition)
|
63
|
-
|
64
|
-
generated_html = documenter.to_html_fragment
|
65
|
-
generated_markdown = documenter.to_markdown
|
66
|
-
|
67
|
-
expect(generated_html).not_to include('<h3>Request parameters</h3>')
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'generates HTML from an ActionDefinition with a casted route param' do
|
71
|
-
definition = Apiculture::ActionDefinition.new
|
72
|
-
|
73
|
-
definition.description = "This adds a topping to a pancake"
|
74
|
-
|
75
|
-
definition.route_parameters << Apiculture::RouteParameter.new(:topping_id, 'ID of the pancake topping', Integer, cast: :to_i)
|
76
|
-
definition.http_verb = 'get'
|
77
|
-
definition.path = '/pancake/:topping_id'
|
78
|
-
|
79
|
-
documenter = described_class.new(definition)
|
80
|
-
|
81
|
-
generated_html = documenter.to_html_fragment
|
82
|
-
generated_markdown = documenter.to_markdown
|
83
|
-
expect(generated_html).to include('<h3>URL parameters</h3>')
|
84
|
-
expect(generated_html).to include('Type after cast')
|
85
|
-
end
|
86
|
-
|
87
|
-
|
88
|
-
it 'generates Markdown from an ActionDefinition with a mountpoint' do
|
89
|
-
definition = Apiculture::ActionDefinition.new
|
90
|
-
|
91
|
-
definition.description = "This action bakes pancakes"
|
92
|
-
|
93
|
-
definition.route_parameters << Apiculture::RouteParameter.new(:pan_id, 'ID of the pancake frying pan')
|
94
|
-
definition.http_verb = 'get'
|
95
|
-
definition.path = '/pancake/:pan_id/bake'
|
96
|
-
|
97
|
-
documenter = described_class.new(definition, '/api/v1')
|
98
|
-
|
99
|
-
generated_markdown = documenter.to_markdown
|
100
|
-
expect(generated_markdown).to include('## GET /api/v1/pancake/:pan_id')
|
101
|
-
end
|
102
|
-
end
|
data/spec/apiculture_spec.rb
DELETED
@@ -1,461 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe "Apiculture" do
|
4
|
-
include Rack::Test::Methods
|
5
|
-
|
6
|
-
before(:each) { @app_class = nil }
|
7
|
-
def app
|
8
|
-
@app_class or raise "No @app_class defined in the example"
|
9
|
-
end
|
10
|
-
|
11
|
-
context 'as API definition DSL' do
|
12
|
-
it 'allows all the standard Siantra DSL to go through without modifications' do
|
13
|
-
@app_class = Class.new(Apiculture::App) do
|
14
|
-
extend Apiculture
|
15
|
-
|
16
|
-
post '/things/*' do
|
17
|
-
params.inspect
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
post '/things/a/b/c/d', {'foo' => 'bar'}
|
22
|
-
expect(last_response.body).to eq("{\"foo\"=>\"bar\", \"splat\"=>[\"a/b/c/d\"], \"captures\"=>[\"a/b/c/d\"]}")
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'flags :captures as a reserved Sinatra parameter when used as a URL param' do
|
26
|
-
expect {
|
27
|
-
Class.new(Apiculture::App) do
|
28
|
-
extend Apiculture
|
29
|
-
route_param :captures, "Something it captures"
|
30
|
-
api_method(:get, '/thing/:captures') { raise "Should never be called" }
|
31
|
-
end
|
32
|
-
}.to raise_error(/\:captures is a reserved magic parameter name/)
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'flags :captures as a reserved Sinatra parameter when used as a request param' do
|
36
|
-
expect {
|
37
|
-
Class.new(Apiculture::App) do
|
38
|
-
extend Apiculture
|
39
|
-
param :captures, "Something it captures", String
|
40
|
-
api_method(:get, '/thing') { raise "Should never be called" }
|
41
|
-
end
|
42
|
-
}.to raise_error(/\:captures is a reserved magic parameter name/)
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'flags :splat as a reserved Sinatra parameter when used as a URL param' do
|
46
|
-
expect {
|
47
|
-
Class.new(Apiculture::App) do
|
48
|
-
extend Apiculture
|
49
|
-
route_param :splat, "Something it splats"
|
50
|
-
api_method(:get, '/thing/:splat') { raise "Should never be called" }
|
51
|
-
end
|
52
|
-
}.to raise_error(/\:splat is a reserved magic parameter name/)
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'flags :splat as a reserved Sinatra parameter when used as a request param' do
|
56
|
-
expect {
|
57
|
-
Class.new(Apiculture::App) do
|
58
|
-
extend Apiculture
|
59
|
-
param :splat, "Something it splats", String
|
60
|
-
api_method(:get, '/thing') { raise "Should never be called" }
|
61
|
-
end
|
62
|
-
}.to raise_error(/\:splat is a reserved magic parameter name/)
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'flags URL and request params of the same name' do
|
66
|
-
expect {
|
67
|
-
Class.new(Apiculture::App) do
|
68
|
-
extend Apiculture
|
69
|
-
route_param :id, 'Id of the thing'
|
70
|
-
param :id, "Something it identifies (conflict)", String
|
71
|
-
api_method(:get, '/thing/:id') { raise "Should never be called" }
|
72
|
-
end
|
73
|
-
}.to raise_error(/\:id mentioned twice/)
|
74
|
-
end
|
75
|
-
|
76
|
-
it "defines a basic API that can be called" do
|
77
|
-
$created_thing = nil
|
78
|
-
@app_class = Class.new(Apiculture::App) do
|
79
|
-
extend Apiculture
|
80
|
-
|
81
|
-
desc "Create a Thing with a name"
|
82
|
-
route_param :id, "The ID of the thing"
|
83
|
-
required_param :name, "Name of the thing", String
|
84
|
-
api_method :post, '/thing/:id' do | thing_id |
|
85
|
-
$created_thing = {id: thing_id, name: params[:name]}
|
86
|
-
'Wild success'
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
post '/thing/123', {name: 'Monsieur Thing'}
|
91
|
-
expect(last_response.body).to eq('Wild success')
|
92
|
-
expect($created_thing).to eq({id: '123', name: 'Monsieur Thing'})
|
93
|
-
end
|
94
|
-
|
95
|
-
it "serves the API documentation at a given URL using serve_api_documentation_at" do
|
96
|
-
$created_thing = nil
|
97
|
-
@app_class = Class.new(Apiculture::App) do
|
98
|
-
extend Apiculture
|
99
|
-
|
100
|
-
desc "Create a Thing with a name"
|
101
|
-
required_param :name, "Name of the thing", String
|
102
|
-
api_method( :post, '/thing/:id') {}
|
103
|
-
serve_api_documentation_at('/documentation')
|
104
|
-
end
|
105
|
-
|
106
|
-
get '/documentation'
|
107
|
-
expect(last_response['Content-Type']).to include('text/html')
|
108
|
-
expect(last_response.body).to include('Create a Thing')
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'raises when a required param is not provided' do
|
112
|
-
@app_class = Class.new(Apiculture::App) do
|
113
|
-
extend Apiculture
|
114
|
-
|
115
|
-
required_param :name, "Name of the thing", String
|
116
|
-
api_method :post, '/thing' do
|
117
|
-
raise "Should never be called"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
expect {
|
122
|
-
post '/thing', {}
|
123
|
-
}.to raise_error('Missing parameter :name')
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'verifies the parameter type' do
|
127
|
-
@app_class = Class.new(Apiculture::App) do
|
128
|
-
extend Apiculture
|
129
|
-
|
130
|
-
required_param :number, "Number of the thing", Integer
|
131
|
-
api_method :post, '/thing' do
|
132
|
-
raise "Should never be called"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
expect {
|
137
|
-
post '/thing', {number: '123'}
|
138
|
-
}.to raise_error('Received String, expected Integer for :number')
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'supports an arbitrary object with === as a type specifier for a parameter' do
|
142
|
-
custom_matcher = Class.new do
|
143
|
-
def ===(value)
|
144
|
-
value == "Magic word"
|
145
|
-
end
|
146
|
-
end.new
|
147
|
-
|
148
|
-
@app_class = Class.new(Apiculture::App) do
|
149
|
-
extend Apiculture
|
150
|
-
|
151
|
-
required_param :pretty_please, "Only a magic word will do", custom_matcher
|
152
|
-
api_method :post, '/thing' do
|
153
|
-
'Ohai!'
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
post '/thing', {pretty_please: 'Magic word'}
|
158
|
-
expect(last_response).to be_ok
|
159
|
-
|
160
|
-
expect {
|
161
|
-
post '/thing', {pretty_please: 'not the magic word you are looking for'}
|
162
|
-
}.to raise_error(Apiculture::ParameterTypeMismatch)
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'suppresses parameters that are not defined in the action definition' do
|
166
|
-
@app_class = Class.new(Apiculture::App) do
|
167
|
-
extend Apiculture
|
168
|
-
|
169
|
-
api_method :post, '/thing' do
|
170
|
-
raise ":evil_ssh_injection should have wiped from params{}" if params[:evil_ssh_injection]
|
171
|
-
'All is well'
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
post '/thing', {evil_ssh_injection: 'I am Homakov!'}
|
176
|
-
expect(last_response).to be_ok
|
177
|
-
end
|
178
|
-
|
179
|
-
it 'allows route parameters that are not mentioned in the action definition, but are given in Sinatra path' do
|
180
|
-
@app_class = Class.new(Apiculture::App) do
|
181
|
-
extend Apiculture
|
182
|
-
|
183
|
-
api_method :post, '/api-thing/:id_of_thing' do |id|
|
184
|
-
raise 'id_of_thing must be passed' unless id == '123456'
|
185
|
-
raise "id_of_thing must be present in params, but they were #{params.inspect}" unless params.keys.include?('id_of_thing')
|
186
|
-
raise "id_of_thing must be string-accessible in params" unless params['id_of_thing'] == '123456'
|
187
|
-
raise "id_of_thing must be symbol-accessible in params" unless params[:id_of_thing] == '123456'
|
188
|
-
'All is well'
|
189
|
-
end
|
190
|
-
|
191
|
-
post '/vanilla-thing/:id_of_thing' do |id|
|
192
|
-
raise 'id_of_thing must be passed' unless id == '123456'
|
193
|
-
raise "id_of_thing must be present in params, but they were #{params.inspect}" unless params.keys.include?('id_of_thing')
|
194
|
-
raise "id_of_thing must be string-accessible in params" unless params['id_of_thing'] == '123456'
|
195
|
-
raise "id_of_thing must be symbol-accessible in params" unless params[:id_of_thing] == '123456'
|
196
|
-
'All is well'
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
post '/vanilla-thing/123456'
|
201
|
-
expect(last_response).to be_ok
|
202
|
-
|
203
|
-
post '/api-thing/123456'
|
204
|
-
expect(last_response).to be_ok
|
205
|
-
end
|
206
|
-
|
207
|
-
it 'does not clobber the status set in a separate mutating call when using json_response' do
|
208
|
-
@app_class = Class.new(Apiculture::App) do
|
209
|
-
extend Apiculture
|
210
|
-
|
211
|
-
api_method :post, '/api/:id' do
|
212
|
-
status 201
|
213
|
-
json_response({was_created: true})
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
post '/api/123'
|
218
|
-
expect(last_response.status).to eq(201)
|
219
|
-
end
|
220
|
-
|
221
|
-
it 'raises when describing a route parameter that is not included in the path' do
|
222
|
-
expect {
|
223
|
-
Class.new(Apiculture::App) do
|
224
|
-
extend Apiculture
|
225
|
-
route_param :thing_id, "The ID of the thing"
|
226
|
-
api_method(:get, '/thing/:id') { raise "Should never be called" }
|
227
|
-
end
|
228
|
-
}.to raise_error('Parameter :thing_id not present in path "/thing/:id"')
|
229
|
-
end
|
230
|
-
|
231
|
-
it 'returns a 404 when a non existing route is called' do
|
232
|
-
@app_class = Class.new(Apiculture::App) do
|
233
|
-
extend Apiculture
|
234
|
-
|
235
|
-
api_method :post, '/api' do
|
236
|
-
[1]
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
post '/api-404'
|
241
|
-
expect(last_response.status).to eq(404)
|
242
|
-
end
|
243
|
-
|
244
|
-
it 'applies a symbol typecast by calling a method on the parameter value' do
|
245
|
-
@app_class = Class.new(Apiculture::App) do
|
246
|
-
extend Apiculture
|
247
|
-
|
248
|
-
required_param :number, "Number of the thing", Integer, :cast => :to_i
|
249
|
-
api_method :post, '/thing' do
|
250
|
-
raise "Not cast" unless params[:number] == 123
|
251
|
-
'Total success'
|
252
|
-
end
|
253
|
-
end
|
254
|
-
post '/thing', {number: '123'}
|
255
|
-
expect(last_response.body).to eq('Total success')
|
256
|
-
end
|
257
|
-
|
258
|
-
it 'ensures current behaviour for route params is not changed' do
|
259
|
-
@app_class = Class.new(Apiculture::App) do
|
260
|
-
extend Apiculture
|
261
|
-
|
262
|
-
route_param :number, "Number of the thing"
|
263
|
-
api_method :post, '/thing/:number' do
|
264
|
-
raise "Casted to int" if params[:number] == 123
|
265
|
-
'Total success'
|
266
|
-
end
|
267
|
-
end
|
268
|
-
post '/thing/123'
|
269
|
-
expect(last_response.body).to eq('Total success')
|
270
|
-
end
|
271
|
-
|
272
|
-
it 'supports returning a rack triplet' do
|
273
|
-
@app_class = Class.new(Apiculture::App) do
|
274
|
-
extend Apiculture
|
275
|
-
api_method :get, '/rack' do
|
276
|
-
[402, {'X-Money-In-The-Bank' => 'yes, please'}, ['Buy bitcoin']]
|
277
|
-
end
|
278
|
-
end
|
279
|
-
get '/rack'
|
280
|
-
expect(last_response.status).to eq 402
|
281
|
-
expect(last_response.body).to eq 'Buy bitcoin'
|
282
|
-
end
|
283
|
-
|
284
|
-
it 'ensures current behaviour when no route params are present does not change' do
|
285
|
-
@app_class = Class.new(Apiculture::App) do
|
286
|
-
extend Apiculture
|
287
|
-
|
288
|
-
param :number, "Number of the thing", Integer, cast: :to_i
|
289
|
-
api_method :post, '/thing' do
|
290
|
-
raise "Behaviour changed" unless params[:number] == 123
|
291
|
-
'Total success'
|
292
|
-
end
|
293
|
-
end
|
294
|
-
post '/thing', {number: '123'}
|
295
|
-
expect(last_response.body).to eq('Total success')
|
296
|
-
end
|
297
|
-
|
298
|
-
it 'applies a symbol typecast by calling a method on the route parameter value' do
|
299
|
-
@app_class = Class.new(Apiculture::App) do
|
300
|
-
extend Apiculture
|
301
|
-
|
302
|
-
route_param :number, "Number of the thing", Integer, :cast => :to_i
|
303
|
-
api_method :post, '/thing/:number' do
|
304
|
-
raise "Not cast" unless params[:number] == 123
|
305
|
-
'Total success'
|
306
|
-
end
|
307
|
-
end
|
308
|
-
post '/thing/123'
|
309
|
-
expect(last_response.body).to eq('Total success')
|
310
|
-
end
|
311
|
-
|
312
|
-
|
313
|
-
it 'cast block arguments to the right type', run: true do
|
314
|
-
@app_class = Class.new(Apiculture::App) do
|
315
|
-
extend Apiculture
|
316
|
-
|
317
|
-
route_param :number, "Number of the thing", Integer, :cast => :to_i
|
318
|
-
api_method :post, '/thing/:number' do |number|
|
319
|
-
raise "Not cast" unless number.is_a?(Integer)
|
320
|
-
'Total success'
|
321
|
-
end
|
322
|
-
end
|
323
|
-
post '/thing/123'
|
324
|
-
expect(last_response.body).to eq('Total success')
|
325
|
-
|
326
|
-
# Double checking that bignums are okay, too
|
327
|
-
bignum = 10**30
|
328
|
-
post "/thing/#{bignum}"
|
329
|
-
expect(last_response.body).to eq('Total success')
|
330
|
-
end
|
331
|
-
|
332
|
-
|
333
|
-
it 'merges route_params and regular params' do
|
334
|
-
@app_class = Class.new(Apiculture::App) do
|
335
|
-
extend Apiculture
|
336
|
-
|
337
|
-
param :number, "Number of the thing", Integer, :cast => :to_i
|
338
|
-
route_param :id, "Id of the thingy", Integer, :cast => :to_i
|
339
|
-
route_param :awesome, "Hash of the thingy"
|
340
|
-
|
341
|
-
api_method :post, '/thing/:id/:awesome' do |id|
|
342
|
-
raise 'Not merged' unless params.has_key?("id")
|
343
|
-
raise 'Not merged' unless params.has_key?("awesome")
|
344
|
-
'Thanks'
|
345
|
-
end
|
346
|
-
end
|
347
|
-
post '/thing/1/true', {number: '123'}
|
348
|
-
expect(last_response.body).to eq('Thanks')
|
349
|
-
end
|
350
|
-
|
351
|
-
|
352
|
-
it 'applies a Proc typecast by calling the proc (for example - for ISO8601 time)' do
|
353
|
-
@app_class = Class.new(Apiculture::App) do
|
354
|
-
extend Apiculture
|
355
|
-
|
356
|
-
required_param :when, "When it happened", Time, cast: ->(v){ Time.parse(v) }
|
357
|
-
api_method :post, '/occurrence' do
|
358
|
-
raise "Not cast" unless params[:when].year == 2015
|
359
|
-
raise "Not cast" unless params[:when].month == 7
|
360
|
-
'Total success'
|
361
|
-
end
|
362
|
-
end
|
363
|
-
post '/occurrence', {when: '2015-07-05T22:16:18Z'}
|
364
|
-
expect(last_response.body).to eq('Total success')
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
context 'Sinatra instance method extensions' do
|
369
|
-
it 'adds support for json_response' do
|
370
|
-
@app_class = Class.new(Apiculture::App) do
|
371
|
-
extend Apiculture
|
372
|
-
api_method :get, '/some-json' do
|
373
|
-
json_response({foo: 'bar'})
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
get '/some-json'
|
378
|
-
expect(last_response).to be_ok
|
379
|
-
expect(last_response['Content-Type']).to include('application/json')
|
380
|
-
parsed_body = JSON.load(last_response.body)
|
381
|
-
expect(parsed_body['foo']).to eq('bar')
|
382
|
-
end
|
383
|
-
|
384
|
-
it 'adds support for json_response to set http status code', run: true do
|
385
|
-
@app_class = Class.new(Apiculture::App) do
|
386
|
-
extend Apiculture
|
387
|
-
api_method :post, '/some-json' do
|
388
|
-
json_response({foo: 'bar'}, status: 201)
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
post '/some-json'
|
393
|
-
expect(last_response.status).to eq(201)
|
394
|
-
end
|
395
|
-
|
396
|
-
it 'adds support for json_halt' do
|
397
|
-
@app_class = Class.new(Apiculture::App) do
|
398
|
-
extend Apiculture
|
399
|
-
api_method :get, '/simple-halt' do
|
400
|
-
json_halt "Nein."
|
401
|
-
raise "This should never be called"
|
402
|
-
end
|
403
|
-
api_method :get, '/halt-with-custom-status' do
|
404
|
-
json_halt 'Nein.', status: 503
|
405
|
-
raise "This should never be called"
|
406
|
-
end
|
407
|
-
api_method :get, '/halt-with-error-payload' do
|
408
|
-
json_halt 'Nein.', teapot: true
|
409
|
-
raise "This should never be called"
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
get '/simple-halt'
|
414
|
-
expect(last_response.status).to eq(400)
|
415
|
-
expect(last_response['Content-Type']).to include('application/json')
|
416
|
-
parsed_body = JSON.load(last_response.body)
|
417
|
-
expect(parsed_body).to eq({"error"=>"Nein."})
|
418
|
-
|
419
|
-
get '/halt-with-error-payload'
|
420
|
-
expect(last_response.status).to eq(400)
|
421
|
-
expect(last_response['Content-Type']).to include('application/json')
|
422
|
-
parsed_body = JSON.load(last_response.body)
|
423
|
-
expect(parsed_body).to eq({"error"=>"Nein.", "teapot"=>true})
|
424
|
-
end
|
425
|
-
|
426
|
-
# Mocks didn't play well with setting the status in a sinatra action
|
427
|
-
class NilTestAction < Apiculture::Action
|
428
|
-
def perform
|
429
|
-
status 204
|
430
|
-
nil
|
431
|
-
end
|
432
|
-
end
|
433
|
-
it 'allows returning an empty body when the status is 204' do
|
434
|
-
@app_class = Class.new(Apiculture::App) do
|
435
|
-
extend Apiculture
|
436
|
-
api_method :get, '/nil204' do
|
437
|
-
action_result NilTestAction
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
get '/nil204'
|
442
|
-
expect(last_response.status).to eq(204)
|
443
|
-
expect(last_response.body).to be_empty
|
444
|
-
end
|
445
|
-
|
446
|
-
it "does not allow returning an empty body when the status isn't 204" do
|
447
|
-
# Mock out the perform call so that status doesn't change from the default of 200
|
448
|
-
expect_any_instance_of(NilTestAction).to receive(:perform).with(any_args).and_return(nil)
|
449
|
-
@app_class = Class.new(Apiculture::App) do
|
450
|
-
extend Apiculture
|
451
|
-
api_method :get, '/nil200' do
|
452
|
-
action_result NilTestAction
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
expect{
|
457
|
-
get '/nil200'
|
458
|
-
}.to raise_error(RuntimeError)
|
459
|
-
end
|
460
|
-
end
|
461
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
|
4
|
-
require 'rspec'
|
5
|
-
require 'apiculture'
|
6
|
-
require 'rack'
|
7
|
-
require 'rack/test'
|
8
|
-
|
9
|
-
# Requires supporting files with custom matchers and macros, etc,
|
10
|
-
# in ./support/ and its subdirectories.
|
11
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
12
|
-
|
13
|
-
RSpec.configure do |config|
|
14
|
-
|
15
|
-
end
|