Page MenuHomePhorge

No OneTemporary

Size
5 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/tesla/middleware/json.ex b/lib/tesla/middleware/json.ex
index ae8751f..92cc439 100644
--- a/lib/tesla/middleware/json.ex
+++ b/lib/tesla/middleware/json.ex
@@ -1,98 +1,103 @@
defmodule Tesla.Middleware.JSON do
# NOTE: text/javascript added to support Facebook Graph API.
# see https://github.com/teamon/tesla/pull/13
@content_types ["application/json", "text/javascript"]
@default_engine Poison
@doc """
Encode and decode response body as JSON
Available options:
- `:decode` - decoding function
- `:encode` - encoding function
- `:engine` - encode/decode engine, e.g `Poison` or `JSX` (defaults to Poison)
- `:engine_opts` - optional engine options
"""
def call(env, next, opts) do
opts = opts || []
env
|> encode(opts)
|> Tesla.run(next)
|> decode(opts)
end
def encode(env, opts) do
if encodable?(env) do
env
|> Map.update!(:body, &encode_body(&1, opts))
|> Tesla.Middleware.Headers.call([], %{"content-type" => "application/json"})
else
env
end
end
defp encode_body(%Stream{} = body, opts), do: encode_stream(body, opts)
defp encode_body(body, opts) when is_function(body), do: encode_stream(body, opts)
defp encode_body(body, opts), do: process(body, :encode, opts)
defp encode_stream(body, opts) do
Stream.map body, fn item -> encode_body(item, opts) <> "\n" end
end
def encodable?(env), do: env.body != nil
def decode(env, opts) do
if decodable?(env) do
Map.update!(env, :body, &process(&1, :decode, opts))
else
env
end
end
def decodable?(env), do: decodable_body?(env) && decodable_content_type?(env)
- def decodable_body?(env), do: is_binary(env.body) || is_list(env.body)
+
+ def decodable_body?(env) do
+ (is_binary(env.body) && env.body != "") ||
+ (is_list(env.body) && env.body != [])
+ end
+
def decodable_content_type?(env) do
case env.headers["content-type"] do
nil -> false
content_type -> Enum.any?(@content_types, &String.starts_with?(content_type, &1))
end
end
defp process(data, op, opts) do
with {:ok, value} <- do_process(data, op, opts) do
value
else
{:error, reason} -> raise %Tesla.Error{message: "JSON #{op} error: #{inspect reason}", reason: reason}
end
end
defp do_process(data, op, opts) do
if fun = opts[op] do # :encode/:decode
fun.(data)
else
engine = Keyword.get(opts, :engine, @default_engine)
opts = Keyword.get(opts, :engine_opts, [])
apply(engine, op, [data, opts])
end
end
end
defmodule Tesla.Middleware.DecodeJson do
def call(env, next, opts \\ []) do
env
|> Tesla.run(next)
|> Tesla.Middleware.JSON.decode(opts)
end
end
defmodule Tesla.Middleware.EncodeJson do
def call(env, next, opts \\ []) do
env
|> Tesla.Middleware.JSON.encode(opts)
|> Tesla.run(next)
end
end
diff --git a/test/tesla/middleware/json_test.exs b/test/tesla/middleware/json_test.exs
index 3a44453..5f21bdf 100644
--- a/test/tesla/middleware/json_test.exs
+++ b/test/tesla/middleware/json_test.exs
@@ -1,65 +1,71 @@
defmodule JsonTest do
use ExUnit.Case
use Tesla.Middleware.TestCase, middleware: Tesla.Middleware.JSON
use Tesla.Middleware.TestCase, middleware: Tesla.Middleware.DecodeJson
use Tesla.Middleware.TestCase, middleware: Tesla.Middleware.EncodeJson
defmodule Client do
use Tesla
plug Tesla.Middleware.JSON
adapter fn (env) ->
{status, headers, body} = case env.url do
"/decode" ->
{200, %{'Content-Type' => 'application/json'}, "{\"value\": 123}"}
"/encode" ->
{200, %{'Content-Type' => 'application/json'}, env.body |> String.replace("foo", "baz")}
"/empty" ->
{200, %{'Content-Type' => 'application/json'}, nil}
+ "/empty-string" ->
+ {200, %{'Content-Type' => 'application/json'}, ""}
"/invalid-content-type" ->
{200, %{'Content-Type' => 'text/plain'}, "hello"}
"/facebook" ->
{200, %{'Content-Type' => 'text/javascript'}, "{\"friends\": 1000000}"}
end
%{env | status: status, headers: headers, body: body}
end
end
defmodule CustomClient do
use Tesla
plug Tesla.Middleware.DecodeJson, engine: Poison, engine_opts: [keys: :atoms]
adapter fn (env) ->
case env.url do
"/decode" ->
{200, %{'Content-Type' => 'application/json'}, "{\"value\": 123}"}
end
end
end
test "decode JSON body" do
assert Client.get("/decode").body == %{"value" => 123}
end
test "do not decode empty body" do
assert Client.get("/empty").body == nil
end
+ test "do not decode empty string body" do
+ assert Client.get("/empty-string").body == ""
+ end
+
test "decode only if Content-Type is application/json or test/json" do
assert Client.get("/invalid-content-type").body == "hello"
end
test "encode body as JSON" do
assert Client.post("/encode", %{"foo" => "bar"}).body == %{"baz" => "bar"}
end
test "decode if Content-Type is text/javascript" do
assert Client.get("/facebook").body == %{"friends" => 1000000}
end
end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jan 21, 4:51 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55738
Default Alt Text
(5 KB)

Event Timeline