JSON and UrlEncoded request middleware now encode body conditionally

These middleware now pay attention to "Content-Type" of the request.
Each will only encode the body if the content-type value matches.

When a body is present but no Content-Type, the middleware higher on
the stack will use its encoding.

This makes it possible to keep both middlewares on the stack and choose
encoding type by Content-Type switching.
This commit is contained in:
Mislav Marohnić 2011-03-02 03:39:02 +01:00
parent 37542f953a
commit 862c98344f
3 changed files with 60 additions and 25 deletions

View File

@ -1,9 +1,11 @@
module Faraday
class Request::JSON < Faraday::Middleware
class Request::JSON < Request::UrlEncoded
self.mime_type = 'application/json'.freeze
class << self
attr_accessor :adapter
end
# loads the JSON encoder either from yajl-ruby or activesupport
begin
begin
@ -21,12 +23,9 @@ module Faraday
end
def call(env)
if data = env[:body]
env[:request_headers]['Content-Type'] = 'application/json'
unless data.respond_to?(:to_str)
env[:body] = self.class.adapter.encode data
end
match_content_type(env) do |data|
# encode with the first successfully loaded adapter
env[:body] = self.class.adapter.encode data
end
@app.call env
end

View File

@ -1,14 +1,31 @@
module Faraday
class Request::UrlEncoded < Faraday::Middleware
def call(env)
if data = env[:body]
env[:request_headers]['Content-Type'] = 'application/x-www-form-urlencoded'
class << self
attr_accessor :mime_type
end
self.mime_type = 'application/x-www-form-urlencoded'.freeze
unless data.respond_to?(:to_str)
env[:body] = Faraday::Utils.build_nested_query data
end
def call(env)
match_content_type(env) do |data|
env[:body] = Faraday::Utils.build_nested_query data
end
@app.call env
end
def match_content_type(env)
type = request_type(env)
if env[:body] and (type.empty? or type == self.class.mime_type)
env[:request_headers]['Content-Type'] ||= self.class.mime_type
yield env[:body] unless env[:body].respond_to?(:to_str)
end
end
def request_type(env)
type = env[:request_headers]['Content-Type'].to_s
type = type.split(';', 2).first if type.index(';')
type
end
end
end

View File

@ -1,8 +1,10 @@
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
require 'rack/utils'
class RequestMiddlewareTest < Faraday::TestCase
def setup
@conn = Faraday.new do |b|
b.request :url_encoded
b.request :json
b.adapter :test do |stub|
stub.post('/echo') do |env|
@ -12,30 +14,47 @@ class RequestMiddlewareTest < Faraday::TestCase
end
end
end
def test_does_nothing_without_payload
response = @conn.post('/echo')
assert_nil response.headers['Content-Type']
assert response.body.empty?
end
def test_encodes_hash
response = @conn.post('/echo', { :fruit => %w[apples oranges] })
def test_ignores_custom_content_type
response = @conn.post('/echo', { :some => 'data' }, 'content-type' => 'application/x-foo')
assert_equal 'application/x-foo', response.headers['Content-Type']
assert_equal({ :some => 'data' }, response.body)
end
def test_json_encodes_hash
response = @conn.post('/echo', { :fruit => %w[apples oranges] }, 'content-type' => 'application/json')
assert_equal 'application/json', response.headers['Content-Type']
assert_equal '{"fruit":["apples","oranges"]}', response.body
end
def test_skips_encoding_for_strings
response = @conn.post('/echo', '{"a":"b"}')
def test_json_skips_encoding_for_strings
response = @conn.post('/echo', '{"a":"b"}', 'content-type' => 'application/json')
assert_equal 'application/json', response.headers['Content-Type']
assert_equal '{"a":"b"}', response.body
end
def test_url_encoded
@conn.builder.swap Faraday::Request::JSON, Faraday::Request::UrlEncoded
def test_url_encoded_no_header
response = @conn.post('/echo', { :fruit => %w[apples oranges] })
assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type']
assert_equal 'fruit[]=apples&fruit[]=oranges', response.body
end
def test_url_encoded_with_header
response = @conn.post('/echo', {'a'=>123}, 'content-type' => 'application/x-www-form-urlencoded')
assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type']
assert_equal 'a=123', response.body
end
def test_url_encoded_nested
response = @conn.post('/echo', { :user => {:name => 'Mislav', :web => 'mislav.net'} })
assert_equal 'application/x-www-form-urlencoded', response.headers['Content-Type']
expected = { 'user' => {'name' => 'Mislav', 'web' => 'mislav.net'} }
assert_equal expected, Rack::Utils.parse_nested_query(response.body)
end
end