Skip to content

Commit 2cb79e6

Browse files
committedMar 26, 2024
feat: Tidy up code and add tests
1 parent 5420ab0 commit 2cb79e6

File tree

4 files changed

+174
-55
lines changed

4 files changed

+174
-55
lines changed
 

‎lib/apia/rack.rb

+16-10
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,14 @@ def triplet_for_exception(exception)
152152

153153
class << self
154154

155-
# Return a triplet for the given body.
155+
# Return a plain text triplet for the given body.
156156
#
157-
# @param body [Hash, Array]
157+
# @param body [String]
158158
# @param status [Integer]
159159
# @param headers [Hash]
160160
# @return [Array]
161161
def plain_triplet(body, status: 200, headers: {})
162-
[
163-
status,
164-
headers.merge('content-type' => 'text/plain', 'content-length' => body.bytesize.to_s),
165-
[body]
166-
]
162+
response_triplet(body, content_type: 'text/plain', status: status, headers: headers)
167163
end
168164

169165
# Return a JSON-ready triplet for the given body.
@@ -173,11 +169,21 @@ def plain_triplet(body, status: 200, headers: {})
173169
# @param headers [Hash]
174170
# @return [Array]
175171
def json_triplet(body, status: 200, headers: {})
176-
body_as_json = body.to_json
172+
response_triplet(body.to_json, content_type: 'application/json', status: status, headers: headers)
173+
end
174+
175+
# Return a triplet for the given body.
176+
#
177+
# @param body [Hash, Array]
178+
# @param content_type [String]
179+
# @param status [Integer]
180+
# @param headers [Hash]
181+
# @return [Array]
182+
def response_triplet(body, content_type:, status: 200, headers: {})
177183
[
178184
status,
179-
headers.merge('content-type' => 'application/json', 'content-length' => body_as_json.bytesize.to_s),
180-
[body_as_json]
185+
headers.merge('content-type' => content_type, 'content-length' => body.bytesize.to_s),
186+
[body]
181187
]
182188
end
183189

‎lib/apia/response.rb

+17-6
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
module Apia
77
class Response
88

9+
TYPES = [
10+
JSON = :json,
11+
PLAIN = :plain
12+
].freeze
13+
914
attr_accessor :status
1015
attr_reader :fields
1116
attr_reader :headers
1217
attr_writer :body
13-
attr_writer :type
1418

1519
def initialize(request, endpoint)
1620
@request = request
@@ -21,6 +25,11 @@ def initialize(request, endpoint)
2125
@headers = {}
2226
end
2327

28+
def plain!
29+
@type = PLAIN
30+
@body = ''
31+
end
32+
2433
# Add a field value for this endpoint
2534
#
2635
# @param name [Symbol]
@@ -55,17 +64,19 @@ def body
5564
end
5665

5766
def type
58-
@type || :json
67+
@type || JSON
5968
end
6069

6170
# Return the rack triplet for this response
6271
#
6372
# @return [Array]
6473
def rack_triplet
65-
return Rack.json_triplet(body, headers: @headers, status: @status) if type == :json
66-
return Rack.plain_triplet(body, headers: @headers, status: @status) if type == :plain
67-
68-
raise "Unknown response type '#{type}'"
74+
case type
75+
when JSON
76+
Rack.json_triplet(body, headers: headers, status: status)
77+
when PLAIN
78+
Rack.plain_triplet(body, headers: headers, status: status)
79+
end
6980
end
7081

7182
end

‎spec/specs/apia/rack_spec.rb

+43
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,49 @@ def call(_env)
351351
end
352352
end
353353

354+
context '.plain_triplet' do
355+
it 'should return json encoded data' do
356+
data = 'hello world'
357+
triplet = Apia::Rack.plain_triplet(data)
358+
expect(triplet).to be_a Array
359+
expect(triplet[0]).to eq 200
360+
expect(triplet[1]).to be_a Hash
361+
expect(triplet[2]).to be_a Array
362+
expect(triplet[2][0]).to eq 'hello world'
363+
end
364+
365+
it 'should set the content type' do
366+
data = 'hello world'
367+
triplet = Apia::Rack.plain_triplet(data)
368+
expect(triplet).to be_a Array
369+
expect(triplet[1]['content-type']).to eq 'text/plain'
370+
end
371+
372+
it 'should set the content length' do
373+
data = 'hello world'
374+
triplet = Apia::Rack.plain_triplet(data)
375+
expect(triplet).to be_a Array
376+
expect(triplet[1]['content-length']).to eq '11'
377+
end
378+
379+
it 'should set the status' do
380+
data = 'hello world'
381+
triplet = Apia::Rack.plain_triplet(data, status: 400)
382+
expect(triplet).to be_a Array
383+
expect(triplet[0]).to eq 400
384+
end
385+
386+
it 'should merge additional headers' do
387+
data = 'hello world'
388+
triplet = Apia::Rack.plain_triplet(data, headers: { 'x-something' => 'hello' })
389+
expect(triplet).to be_a Array
390+
expect(triplet[1]).to be_a Hash
391+
expect(triplet[1]['x-something']).to eq 'hello'
392+
expect(triplet[1]['content-length']).to eq '11'
393+
expect(triplet[1]['content-type']).to eq 'text/plain'
394+
end
395+
end
396+
354397
context '.error_triplet' do
355398
it 'should format the JSON appropriately' do
356399
triplet = Apia::Rack.error_triplet('example_error', description: 'Some example', detail: { hello: 'world' })

‎spec/specs/apia/response_spec.rb

+98-39
Original file line numberDiff line numberDiff line change
@@ -34,52 +34,111 @@
3434
end
3535

3636
context '#rack_triplet' do
37-
it 'should return 200 by default' do
38-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
39-
response = Apia::Response.new(request, endpoint)
40-
expect(response.rack_triplet[0]).to eq 200
41-
end
37+
context 'with a JSON response' do
38+
it 'should return 200 by default' do
39+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
40+
response = Apia::Response.new(request, endpoint)
41+
expect(response.rack_triplet[0]).to eq 200
42+
end
4243

43-
it 'should return whatever the status is set to' do
44-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
45-
response = Apia::Response.new(request, endpoint)
46-
response.status = 403
47-
expect(response.rack_triplet[0]).to eq 403
48-
end
44+
it 'should return whatever the status is set to' do
45+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
46+
response = Apia::Response.new(request, endpoint)
47+
response.status = 403
48+
expect(response.rack_triplet[0]).to eq 403
49+
end
4950

50-
it 'should return the status from the endpoint' do
51-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
52-
endpoint.http_status :created
53-
response = Apia::Response.new(request, endpoint)
54-
expect(response.rack_triplet[0]).to eq 201
55-
end
51+
it 'should return the status from the endpoint' do
52+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
53+
endpoint.http_status :created
54+
response = Apia::Response.new(request, endpoint)
55+
expect(response.rack_triplet[0]).to eq 201
56+
end
5657

57-
it 'should return the headers' do
58-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
59-
response = Apia::Response.new(request, endpoint)
60-
response.add_header 'x-example', 'hello world'
61-
expect(response.rack_triplet[1]['x-example']).to eq 'hello world'
62-
end
58+
it 'should return the headers' do
59+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
60+
response = Apia::Response.new(request, endpoint)
61+
response.add_header 'x-example', 'hello world'
62+
expect(response.rack_triplet[1]['x-example']).to eq 'hello world'
63+
end
6364

64-
it 'should always provide the content-type as json' do
65-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
66-
response = Apia::Response.new(request, endpoint)
67-
expect(response.rack_triplet[1]['content-type']).to eq 'application/json'
68-
end
65+
it 'should always provide the content-type as json' do
66+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
67+
response = Apia::Response.new(request, endpoint)
68+
expect(response.rack_triplet[1]['content-type']).to eq 'application/json'
69+
end
6970

70-
it 'should always set a content-length' do
71-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
72-
response = Apia::Response.new(request, endpoint)
73-
expect(response.rack_triplet[2][0]).to eq '{}'
74-
expect(response.rack_triplet[1]['content-length']).to eq '2'
71+
it 'should always set a content-length' do
72+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
73+
response = Apia::Response.new(request, endpoint)
74+
expect(response.rack_triplet[2][0]).to eq '{}'
75+
expect(response.rack_triplet[1]['content-length']).to eq '2'
76+
end
77+
78+
it 'should return the body if one has been set' do
79+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
80+
response = Apia::Response.new(request, endpoint)
81+
response.body = { hello: 'world' }
82+
expect(response.rack_triplet[2][0]).to eq '{"hello":"world"}'
83+
expect(response.rack_triplet[1]['content-length']).to eq '17'
84+
end
7585
end
7686

77-
it 'should return the body if one has been set' do
78-
endpoint = Apia::Endpoint.create('ExampleEndpoint')
79-
response = Apia::Response.new(request, endpoint)
80-
response.body = { hello: 'world' }
81-
expect(response.rack_triplet[2][0]).to eq '{"hello":"world"}'
82-
expect(response.rack_triplet[1]['content-length']).to eq '17'
87+
context 'with a plain text response' do
88+
it 'should return 200 by default' do
89+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
90+
response = Apia::Response.new(request, endpoint)
91+
response.plain!
92+
expect(response.rack_triplet[0]).to eq 200
93+
end
94+
95+
it 'should return whatever the status is set to' do
96+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
97+
response = Apia::Response.new(request, endpoint)
98+
response.plain!
99+
response.status = 403
100+
expect(response.rack_triplet[0]).to eq 403
101+
end
102+
103+
it 'should return the status from the endpoint' do
104+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
105+
endpoint.http_status :created
106+
response = Apia::Response.new(request, endpoint)
107+
response.plain!
108+
expect(response.rack_triplet[0]).to eq 201
109+
end
110+
111+
it 'should return the headers' do
112+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
113+
response = Apia::Response.new(request, endpoint)
114+
response.plain!
115+
response.add_header 'x-example', 'hello world'
116+
expect(response.rack_triplet[1]['x-example']).to eq 'hello world'
117+
end
118+
119+
it 'should always provide the content-type as plain' do
120+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
121+
response = Apia::Response.new(request, endpoint)
122+
response.plain!
123+
expect(response.rack_triplet[1]['content-type']).to eq 'text/plain'
124+
end
125+
126+
it 'should always set a content-length' do
127+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
128+
response = Apia::Response.new(request, endpoint)
129+
response.plain!
130+
expect(response.rack_triplet[2][0]).to eq ''
131+
expect(response.rack_triplet[1]['content-length']).to eq '0'
132+
end
133+
134+
it 'should return the body if one has been set' do
135+
endpoint = Apia::Endpoint.create('ExampleEndpoint')
136+
response = Apia::Response.new(request, endpoint)
137+
response.plain!
138+
response.body = 'hello world'
139+
expect(response.rack_triplet[2][0]).to eq 'hello world'
140+
expect(response.rack_triplet[1]['content-length']).to eq '11'
141+
end
83142
end
84143
end
85144
end

0 commit comments

Comments
 (0)