Skip to content

Commit

Permalink
Change Reynard Request object to set form data.
Browse files Browse the repository at this point in the history
  • Loading branch information
Manfred committed Jun 18, 2024
1 parent a17fcbc commit 07f4c9b
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 8 deletions.
10 changes: 9 additions & 1 deletion lib/reynard/http/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class Reynard
class Http
# Configures and performs an HTTP request.
class Request
MULTIPART_FORM_DATA = "multipart/form-data"

attr_reader :uri

def initialize(request_context:, serializer_selection:)
Expand Down Expand Up @@ -36,7 +38,13 @@ def request_headers

def build_request
request = request_class.new(uri, request_headers)
if serializer
if @serializer_selection&.content_type == MULTIPART_FORM_DATA
request.set_form(
serializer.data,
serializer.mime_type,
boundary: serializer.multipart_boundary
)
elsif serializer
write_serializer_body(request)
elsif @request_context.body
write_serializer_params(request)
Expand Down
1 change: 1 addition & 0 deletions test/files/ok.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OK!
36 changes: 36 additions & 0 deletions test/integration/reynard_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,42 @@ def teardown
end
end

test 'creates an object using multipart form data' do
with_simple_service do
name = 'An unexpected occurance'
response =
@reynard
.serializer('application/json', nil)
.operation('createBook')
.body({ 'name' => name })
.execute
assert_equal '200', response.code
book = response.object
assert_kind_of Reynard::Models::Book, book
assert_equal name, book.name
end
end

test 'creates an object using multipart form data including a file' do
filename = File.join(FILES_ROOT, 'ok.txt')
with_simple_service do
File.open(filename) do |file|
name = 'An unexpected occurance'
response =
@reynard
.serializer('application/json', nil)
.operation('createBook')
.body({ 'name' => name, 'avatar' => file })
.execute
assert_equal '200', response.code
book = response.object
assert_kind_of Reynard::Models::Book, book
assert_equal name, book.name
assert_equal File.read(filename), book.avatar
end
end
end

test 'returns an error when fetching an object fails' do
with_simple_service do
response = @reynard.operation('fetchBook').params(id: -1).execute
Expand Down
11 changes: 5 additions & 6 deletions test/reynard/context_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,17 +218,16 @@ def setup
end

test 'allows users to post as multipart form data' do
@request_body = nil
stub_request(:post, 'http://example.com/v1/books').with do |request|
@request_body = request.body
end
# Net/HTTP writes the multipart body directly to the socket instead of throught the body
# accessor of the request object so it's not accessible through WebMock.
stub_request(:post, 'http://example.com/v1/books')
data = { 'name' => 'Parcival' }
@context
response = @context
.serializer('application/json', nil)
.operation('createBook')
.body(data)
.execute
assert_includes(@request_body, 'Content-Disposition: form-data')
assert response.success?
end

test 'allows users to post as plain text' do
Expand Down
25 changes: 24 additions & 1 deletion test/support/simple_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ def service(http_request, http_response)
else
respond_with_not_found(http_response)
end
rescue Exception => e
respond_with_internal_server_error(
http_response,
e.class.to_s,
e.message,
e.backtrace
)
end

private
Expand All @@ -34,11 +41,20 @@ def handle_collection(http_request, http_response)
when 'GET'
http_response.body = MultiJson.dump(all)
when 'POST'
book = add(MultiJson.load(http_request.body))
book = add(parse_book(http_request))
http_response.body = MultiJson.dump(book)
end
end

def parse_book(http_request)
case http_request["Content-Type"]
when /^multipart\/form-data/
http_request.query
else
MultiJson.load(http_request.body)
end
end

def handle_member(id, http_response)
book = find(id)
if book
Expand All @@ -53,6 +69,13 @@ def respond_with_not_found(http_response)
http_response.body = MultiJson.dump('error' => 'not_found')
end

def respond_with_internal_server_error(http_response, error, message, backtrace)
http_response.status = 500
http_response.body = MultiJson.dump(
'error' => error, 'message' => message, 'backtrace' => backtrace
)
end

def all
@books
end
Expand Down

0 comments on commit 07f4c9b

Please sign in to comment.