Skip to content

Commit 2128fec

Browse files
committed
Pick serializer based on the request content type.
1 parent 869220e commit 2128fec

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

lib/reynard/context.rb

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,7 @@ def params(params)
3131
end
3232

3333
def body(data)
34-
return unless @request_context.operation
35-
36-
serialized_body = @specification.build_body(@request_context.operation.node, data)
37-
return unless serialized_body
38-
39-
copy(
40-
request: {
41-
headers: @request_context.headers.merge(serialized_body.headers),
42-
body: serialized_body.to_s
43-
}
44-
)
34+
copy(request: { body: self.class.merge_body(@request_context.body, data) })
4535
end
4636

4737
def headers(headers)
@@ -55,14 +45,41 @@ def logger(logger)
5545
)
5646
end
5747

48+
def serializer(content_type, serializer)
49+
copy(
50+
request: {
51+
serializers: @request_context.serializers.merge({ content_type => serializer })
52+
}
53+
)
54+
end
55+
5856
def execute
5957
build_response(build_request.perform)
6058
end
6159

60+
def self.merge_body(current, data)
61+
case current
62+
when NilClass
63+
data
64+
when Hash
65+
current.merge(data)
66+
else
67+
raise(
68+
ArgumentError,
69+
"Please assign the request body once, we can't merge #{data.inspect} into " \
70+
"#{current.inspect}."
71+
)
72+
end
73+
end
74+
6275
private
6376

6477
def build_request_context
65-
RequestContext.new(base_url: @specification.default_base_url, headers: {})
78+
RequestContext.new(
79+
base_url: @specification.default_base_url,
80+
headers: {},
81+
serializers: Reynard.serializers.dup
82+
)
6683
end
6784

6885
def build_response_context
@@ -79,7 +96,16 @@ def copy(request: {}, response: {})
7996
end
8097

8198
def build_request
82-
Reynard::Http::Request.new(request_context: @request_context)
99+
Reynard::Http::Request.new(
100+
request_context: @request_context,
101+
serializer: pick_serializer
102+
)
103+
end
104+
105+
def pick_serializer
106+
@specification
107+
.content(@request_context.operation.node)
108+
.pick_serializer(@request_context.serializers)
83109
end
84110

85111
def build_response(http_response)

lib/reynard/http/request.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ class Http
99
class Request
1010
attr_reader :uri
1111

12-
def initialize(request_context:)
12+
def initialize(request_context:, serializer:)
1313
@request_context = request_context
14+
@serializer = serializer
1415
@uri = URI(@request_context.url)
1516
end
1617

@@ -26,12 +27,18 @@ def request_class
2627
end
2728

2829
def request_headers
29-
{ 'User-Agent' => Reynard.user_agent }.merge(@request_context.headers || {})
30+
{
31+
'User-Agent' => Reynard.user_agent,
32+
'Content-Type' => @serializer&.content_type
33+
}.compact.merge(@request_context.headers || {})
3034
end
3135

3236
def build_request
3337
request = request_class.new(uri, request_headers)
34-
if @request_context.body
38+
if @serializer
39+
@request_context.logger&.debug { @request_context.body }
40+
request.body = @serializer.dump(@request_context.body)
41+
elsif @request_context.body
3542
@request_context.logger&.debug { @request_context.body }
3643
request.body = @request_context.body
3744
end

test/reynard/context_test.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ class Reynard
66
class ContextTest < Reynard::Test
77
def setup
88
@specification = Specification.new(filename: fixture_file('openapi/simple.yml'))
9-
@request_context = RequestContext.new(base_url: @specification.default_base_url, headers: {})
9+
@request_context = RequestContext.new(
10+
base_url: @specification.default_base_url,
11+
headers: {},
12+
serializers: Reynard.serializers.dup
13+
)
1014
@inflector = Inflector.new
1115
@context = Context.new(
1216
specification: @specification, inflector: @inflector, request_context: @request_context
@@ -199,12 +203,28 @@ def setup
199203
assert_equal '200', response.code
200204
assert_equal [1, 2, 3], response.object.map(&:id)
201205
end
206+
207+
test 'allows users to override built-in serializers' do
208+
stub_request(:post, 'http://example.com/v1/books').and_return(body: '{}')
209+
serializer = Mocks::Serializer.new
210+
data = { 'name' => 'Parcival' }
211+
@context
212+
.serializer('application/json', serializer)
213+
.operation('createBook')
214+
.body(data)
215+
.execute
216+
assert_equal([data], serializer.data)
217+
end
202218
end
203219

204220
class BareContextTest < Reynard::Test
205221
def setup
206222
@specification = Specification.new(filename: fixture_file('openapi/bare.yml'))
207-
@request_context = RequestContext.new(base_url: @specification.default_base_url, headers: {})
223+
@request_context = RequestContext.new(
224+
base_url: @specification.default_base_url,
225+
headers: {},
226+
serializers: {}
227+
)
208228
@inflector = Inflector.new
209229
@context = Context.new(
210230
specification: @specification, inflector: @inflector, request_context: @request_context

0 commit comments

Comments
 (0)