Page MenuHomePhorge

No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/tesla/middleware/json.ex b/lib/tesla/middleware/json.ex
index 8110763..b4d28eb 100644
--- a/lib/tesla/middleware/json.ex
+++ b/lib/tesla/middleware/json.ex
@@ -1,110 +1,110 @@
defmodule Tesla.Middleware.JSON do
# NOTE: text/javascript added to support Facebook Graph API.
# see https://github.com/teamon/tesla/pull/13
@default_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
- - `:enable_decoding` - list of additional decodable content-types
+ - `:decode_content_types` - list of additional decodable content-types
"""
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, opts) do
Map.update!(env, :body, &process(&1, :decode, opts))
else
env
end
end
def decodable?(env, opts), do: decodable_body?(env) && decodable_content_type?(env, opts)
def decodable_body?(env) do
(is_binary(env.body) && env.body != "") ||
(is_list(env.body) && env.body != [])
end
def decodable_content_type?(env, opts) do
case env.headers["content-type"] do
nil -> false
content_type -> Enum.any?(content_types(opts), &String.starts_with?(content_type, &1))
end
end
- def content_types(opts), do: @default_content_types ++ Keyword.get(opts, :enable_decoding, [])
+ def content_types(opts), do: @default_content_types ++ Keyword.get(opts, :decode_content_types, [])
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
opts = opts || []
env
|> Tesla.run(next)
|> Tesla.Middleware.JSON.decode(opts)
end
end
defmodule Tesla.Middleware.EncodeJson do
def call(env, next, opts) do
opts = opts || []
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 06bffcf..8e0257b 100644
--- a/test/tesla/middleware/json_test.exs
+++ b/test/tesla/middleware/json_test.exs
@@ -1,117 +1,117 @@
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
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
defmodule CustomClient do
use Tesla
plug Tesla.Middleware.DecodeJson, engine: Poison, engine_opts: [keys: :atoms]
adapter fn (env) ->
{status, headers, body} = case env.url do
"/decode" ->
{200, %{'Content-Type' => 'application/json'}, "{\"value\": 123}"}
end
%{env | status: status, headers: headers, body: body}
end
end
test "decode with custom engine options" do
assert CustomClient.get("/decode").body == %{value: 123}
end
defmodule CustomContentTypeClient do
use Tesla
- plug Tesla.Middleware.JSON, enable_decoding: ["application/x-custom-json"]
+ plug Tesla.Middleware.JSON, decode_content_types: ["application/x-custom-json"]
adapter fn (env) ->
{status, headers, body} = case env.url do
"/decode" ->
{200, %{'Content-Type' => 'application/x-custom-json'}, "{\"value\": 123}"}
end
%{env | status: status, headers: headers, body: body}
end
end
- test "decode if Content-Type specified in :enable_decoding" do
+ test "decode if Content-Type specified in :decode_content_types" do
alias CustomContentTypeClient, as: CCTClient
assert CCTClient.get("/decode").body == %{"value" => 123}
end
defmodule EncodeDecodeJsonClient do
use Tesla
plug Tesla.Middleware.DecodeJson
plug Tesla.Middleware.EncodeJson
adapter fn (env) ->
{status, headers, body} = case env.url do
"/foo2baz" ->
{200, %{'Content-Type' => 'application/json'}, env.body |> String.replace("foo", "baz")}
end
%{env | status: status, headers: headers, body: body}
end
end
test "EncodeJson / DecodeJson work without options" do
alias EncodeDecodeJsonClient, as: EDJClient
assert EDJClient.post("/foo2baz", %{"foo" => "bar"}).body == %{"baz" => "bar"}
end
end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jan 21, 2:36 AM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55642
Default Alt Text
(7 KB)

Event Timeline