diff --git a/lib/absinthe/compose.ex b/lib/absinthe/compose.ex index bcae18a..cbf301a 100644 --- a/lib/absinthe/compose.ex +++ b/lib/absinthe/compose.ex @@ -5,12 +5,16 @@ defmodule Absinthe.Compose do definition: %{ schema_node: %{__private__: private}, name: name - } + }, + context: context } = resolution compose = get_in(private, [:meta, :compose]) compose_module = Keyword.fetch!(compose, :from) - opts = Keyword.get(compose, :opts, []) + + opts = + Keyword.get(compose, :opts, []) + |> forward_hearders(context) {query, variables} = Absinthe.Compose.QueryGenerator.render(resolution) @@ -24,4 +28,11 @@ defmodule Absinthe.Compose do def proxy(module, query, variables, opts, resolution) when is_atom(module) do apply(module, :resolve, [query, variables, opts, resolution]) end + + defp forward_hearders(opts, %{headers_to_forward: headers}) do + [headers: Keyword.get(opts, :headers, []) ++ headers] + |> Keyword.merge(opts) + end + + defp forward_hearders(opts, _context), do: opts end diff --git a/lib/absinthe/plug/forward_headers.ex b/lib/absinthe/plug/forward_headers.ex new file mode 100644 index 0000000..d89d27c --- /dev/null +++ b/lib/absinthe/plug/forward_headers.ex @@ -0,0 +1,28 @@ +defmodule Absinthe.Compose.Plug.ForwardHeader do + @moduledoc """ + This Plug takes the given headers and add it to Absinthe.Plug context in order to be fowarded + on to the Upstream service on the resolver level. + """ + @behaviour Plug + + import Plug.Conn + + def init(opts), do: opts + + @spec call(Plug.Conn.t(), any) :: Plug.Conn.t() + def call(conn, opts) do + headers_to_forward = get_headers(conn, opts) + Absinthe.Plug.put_options(conn, context: %{headers_to_forward: headers_to_forward}) + end + + defp get_headers(conn, header_names) do + Enum.reduce(header_names, [], fn name, acc -> + name = String.downcase(name) + + case get_req_header(conn, name) do + [] -> acc + values -> [{name, values} | acc] + end + end) + end +end diff --git a/mix.exs b/mix.exs index 6672c45..1c55469 100644 --- a/mix.exs +++ b/mix.exs @@ -29,7 +29,7 @@ defmodule AbsintheCompose.MixProject do {:absinthe_plug, "~> 1.5", only: [:dev, :test]}, {:ex_doc, "~> 0.18", only: :dev, runtime: false}, {:jason, "~> 1.0", only: [:dev, :test]}, - {:plug_cowboy, "~> 2.0", only: [:dev, :test]} + {:plug_cowboy, "~> 2.0"} ] end @@ -45,7 +45,7 @@ defmodule AbsintheCompose.MixProject do """, links: %{ github: "https://github.com/SpiffInc/absinthe_compose" - }, + } ] end end diff --git a/test/plug/forward_headers_test.exs b/test/plug/forward_headers_test.exs new file mode 100644 index 0000000..3989c5e --- /dev/null +++ b/test/plug/forward_headers_test.exs @@ -0,0 +1,36 @@ +defmodule Absinthe.Compose.Plug.ForwardHeaderTest do + use ExUnit.Case, async: true + use Plug.Test + + alias Absinthe.Compose.Plug.ForwardHeader + + setup do + ForwardHeader.init(["authorization", "origin"]) + + conn = + conn("post", "/", "") + |> put_req_header("authorization", "some-token") + |> put_req_header("origin", "www.coolwebsite.com") + |> put_req_header("header-to-ignore", "ignored") + + %{ + conn: conn + } + end + + test "fowards given headers to abshinte context", %{conn: conn} do + conn = ForwardHeader.call(conn, ["authorization", "Origin"]) + assert %{context: %{headers_to_forward: headers_to_forward}} = conn.private[:absinthe] + + assert [{"origin", ["www.coolwebsite.com"]}, {"authorization", ["some-token"]}] = + headers_to_forward + + assert length(headers_to_forward) == 2 + end + + test "ignores non-existent headers", %{conn: conn} do + conn = ForwardHeader.call(conn, ["authorization", "origin", "some-giberish"]) + assert %{context: %{headers_to_forward: headers_to_forward}} = conn.private[:absinthe] + assert length(headers_to_forward) == 2 + end +end