From f71064f0238d5098ea98778059500e53b97afb23 Mon Sep 17 00:00:00 2001 From: Aaron Weiker Date: Tue, 15 Dec 2015 11:01:11 -0800 Subject: [PATCH 1/5] Updating example schema to match latest revisions. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f83e88..79c5982 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Allows you to easily mount a GraphQL endpoint in Phoenix. query: %GraphQL.ObjectType{ name: "RootQueryType", fields: %{ - greeting: %GraphQL.FieldDefinition{ + greeting: %{ type: "String", resolve: &TestSchema.greeting/3 } From faf2682747178bd06237ec7744fc8e2fb09a7b20 Mon Sep 17 00:00:00 2001 From: Aaron Weiker Date: Wed, 13 Jan 2016 14:48:45 -0800 Subject: [PATCH 2/5] Allow root_value to be passed along to GraphQL.execute. During plug initialization, allows a function to be defined that will take a conn as input and then return a data structure that can be used as the root_value into the GraphQL.execute method. --- lib/graphql/plug/endpoint.ex | 22 ++++++++++++++-------- test/graphql/plug/endpoint_test.exs | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/graphql/plug/endpoint.ex b/lib/graphql/plug/endpoint.ex index d121a6d..7b7f6be 100644 --- a/lib/graphql/plug/endpoint.ex +++ b/lib/graphql/plug/endpoint.ex @@ -9,16 +9,17 @@ defmodule GraphQL.Plug.Endpoint do {mod, func} -> apply(mod, func, []) s -> s end - %{schema: schema} + root_callback = Keyword.get(opts, :root, %{}) + %{schema: schema, root_callback: root_callback} end def call(%Conn{method: m} = conn, opts) when m in ["GET", "POST"] do - %{schema: schema} = conn.assigns[:graphql_options] || opts + %{schema: schema, root_callback} = conn.assigns[:graphql_options] || opts query = query(conn) cond do - query && use_graphiql?(conn) -> handle_graphiql_call(conn, schema, query) - query -> handle_call(conn, schema, query) + query && use_graphiql?(conn) -> handle_graphiql_call(conn, schema, root_callback, query) + query -> handle_call(conn, schema, root_callback, query) true -> handle_error(conn, "Must provide query string.") end end @@ -27,10 +28,10 @@ defmodule GraphQL.Plug.Endpoint do handle_error(conn, "GraphQL only supports GET and POST requests.") end - defp handle_call(conn, schema, query) do + defp handle_call(conn, schema, root_callback, query) do conn |> put_resp_content_type("application/json") - |> execute(schema, query) + |> execute(schema, root_callback, query) end defp handle_graphiql_call(conn, schema, query) do @@ -48,8 +49,13 @@ defmodule GraphQL.Plug.Endpoint do |> send_resp(400, errors) end - defp execute(conn, schema, query) do - case GraphQL.execute(schema, query) do + defp execute(conn, schema, root_callback, query) do + root_value = case is_function(root_callback) do + true -> root_callback.(conn) + _ -> %{} + end + + case GraphQL.execute(schema, query, root_value) do {:ok, data} -> case Poison.encode(%{data: data}) do {:ok, json} -> send_resp(conn, 200, json) diff --git a/test/graphql/plug/endpoint_test.exs b/test/graphql/plug/endpoint_test.exs index 1112afa..8cc07aa 100644 --- a/test/graphql/plug/endpoint_test.exs +++ b/test/graphql/plug/endpoint_test.exs @@ -19,6 +19,7 @@ defmodule GraphQL.Plug.EndpointTest do end def greeting(_, %{name: name}, _), do: "Hello, #{name}!" + def greeting(%{greeting: name}, _, _), do: "Hello, #{name}!" def greeting(_, _, _), do: greeting(%{}, %{name: "world"}, %{}) end @@ -34,10 +35,23 @@ defmodule GraphQL.Plug.EndpointTest do assert_query TestPlug, {:post, "/", query: "{greeting}"}, {200, success} end + test "root data can be set at request time" do + defmodule TestRootPlug do + use Plug.Builder + def root_eval(_conn), do: %{greeting: "Root"} + plug GraphQL.Plug.Endpoint, [schema: {TestSchema, :schema}, root: &TestRootPlug.root_eval/1 ] + end + + conn = conn(:get, "/", query: "{greeting}") + conn = TestRootPlug.call conn, [] + + assert conn.resp_body == ~S({"data":{"greeting":"Hello, Root!"}}) + end + test "specify schema using {module, fun} syntax" do defmodule TestMFPlug do use Plug.Builder - + plug GraphQL.Plug.Endpoint, schema: {TestSchema, :schema} end success = ~S({"data":{"greeting":"Hello, world!"}}) From e1cb874be5f297e0331e430f810cf68a7f8ca8c7 Mon Sep 17 00:00:00 2001 From: Aaron Weiker Date: Mon, 18 Jan 2016 11:46:35 -0800 Subject: [PATCH 3/5] Responding to initial PR review --- lib/graphql/plug.ex | 3 ++- lib/graphql/plug/endpoint.ex | 41 +++++++++++++++++++---------- mix.lock | 2 +- test/graphql/plug/endpoint_test.exs | 33 ++++++++++++++++++----- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/lib/graphql/plug.ex b/lib/graphql/plug.ex index 3e00b57..1e2e35c 100644 --- a/lib/graphql/plug.ex +++ b/lib/graphql/plug.ex @@ -15,7 +15,8 @@ defmodule GraphQL.Plug do {mod, func} -> apply(mod, func, []) s -> s end - %{schema: schema} + root_value = Keyword.get(opts, :root_value, %{}) + %{root_value: root_value, schema: schema} end def call(conn, opts) do diff --git a/lib/graphql/plug/endpoint.ex b/lib/graphql/plug/endpoint.ex index 7b7f6be..68a4442 100644 --- a/lib/graphql/plug/endpoint.ex +++ b/lib/graphql/plug/endpoint.ex @@ -9,17 +9,18 @@ defmodule GraphQL.Plug.Endpoint do {mod, func} -> apply(mod, func, []) s -> s end - root_callback = Keyword.get(opts, :root, %{}) - %{schema: schema, root_callback: root_callback} + root_value = Keyword.get(opts, :root_value, %{}) + %{root_value: root_value, schema: schema} end def call(%Conn{method: m} = conn, opts) when m in ["GET", "POST"] do - %{schema: schema, root_callback} = conn.assigns[:graphql_options] || opts + %{root_value: root_value, schema: schema} = conn.assigns[:graphql_options] || opts query = query(conn) + evaluated_root_value = evaluate_root_value(conn, root_value) cond do - query && use_graphiql?(conn) -> handle_graphiql_call(conn, schema, root_callback, query) - query -> handle_call(conn, schema, root_callback, query) + query && use_graphiql?(conn) -> handle_graphiql_call(conn, schema, evaluated_root_value, query) + query -> handle_call(conn, schema, evaluated_root_value, query) true -> handle_error(conn, "Must provide query string.") end end @@ -28,14 +29,14 @@ defmodule GraphQL.Plug.Endpoint do handle_error(conn, "GraphQL only supports GET and POST requests.") end - defp handle_call(conn, schema, root_callback, query) do + defp handle_call(conn, schema, root_value, query) do conn |> put_resp_content_type("application/json") - |> execute(schema, root_callback, query) + |> execute(schema, root_value, query) end - defp handle_graphiql_call(conn, schema, query) do - {:ok, data} = GraphQL.execute(schema, query) + defp handle_graphiql_call(conn, schema, root_value, query) do + {:ok, data} = GraphQL.execute(schema, query, root_value) {:ok, result} = Poison.encode(%{data: data}) conn |> put_resp_content_type("text/html") @@ -49,11 +50,7 @@ defmodule GraphQL.Plug.Endpoint do |> send_resp(400, errors) end - defp execute(conn, schema, root_callback, query) do - root_value = case is_function(root_callback) do - true -> root_callback.(conn) - _ -> %{} - end + defp execute(conn, schema, root_value, query) do case GraphQL.execute(schema, query, root_value) do {:ok, data} -> @@ -69,6 +66,22 @@ defmodule GraphQL.Plug.Endpoint do end end + defp evaluate_root_value(conn, {mod, func}) do + apply(mod, func, [conn]) + end + + defp evaluate_root_value(conn, root_value) when is_function(root_value) do + apply(root_value, [conn]) + end + + defp evaluate_root_value(_, root_value) when is_nil(root_value) do + %{} + end + + defp evaluate_root_value(_, root_value) do + root_value + end + defp query(%Conn{params: %{"query" => query}}) do if query && String.strip(query) != "", do: query, else: nil end diff --git a/mix.lock b/mix.lock index 01546f1..72164de 100644 --- a/mix.lock +++ b/mix.lock @@ -2,7 +2,7 @@ "cowlib": {:hex, :cowlib, "1.0.2"}, "earmark": {:hex, :earmark, "0.1.19"}, "ex_doc": {:hex, :ex_doc, "0.11.0"}, - "graphql": {:hex, :graphql, "0.0.9"}, + "graphql": {:hex, :graphql, "0.1.0"}, "plug": {:hex, :plug, "1.0.2"}, "poison": {:hex, :poison, "1.5.0"}, "ranch": {:hex, :ranch, "1.2.0"}} diff --git a/test/graphql/plug/endpoint_test.exs b/test/graphql/plug/endpoint_test.exs index 8cc07aa..e76a1af 100644 --- a/test/graphql/plug/endpoint_test.exs +++ b/test/graphql/plug/endpoint_test.exs @@ -35,23 +35,42 @@ defmodule GraphQL.Plug.EndpointTest do assert_query TestPlug, {:post, "/", query: "{greeting}"}, {200, success} end - test "root data can be set at request time" do - defmodule TestRootPlug do + test "root data can be set at request time using function reference" do + defmodule TestRootPlugWithFunctionReference do use Plug.Builder def root_eval(_conn), do: %{greeting: "Root"} - plug GraphQL.Plug.Endpoint, [schema: {TestSchema, :schema}, root: &TestRootPlug.root_eval/1 ] + plug GraphQL.Plug.Endpoint, [schema: {TestSchema, :schema}, root_value: &TestRootPlugWithFunctionReference.root_eval/1 ] end - conn = conn(:get, "/", query: "{greeting}") - conn = TestRootPlug.call conn, [] + success = ~S({"data":{"greeting":"Hello, Root!"}}) + assert_query TestRootPlugWithFunctionReference, {:get, "/", query: "{greeting}"}, {200, success} + end + + test "root data can be hard coded at init time." do + defmodule TestRootPlugWithHardCodedData do + use Plug.Builder + plug GraphQL.Plug.Endpoint, [schema: {TestSchema, :schema}, root_value: %{greeting: "Hard Coded"}] + end + + success = ~S({"data":{"greeting":"Hello, Hard Coded!"}}) + assert_query TestRootPlugWithHardCodedData, {:get, "/", query: "{greeting}"}, {200, success} + end - assert conn.resp_body == ~S({"data":{"greeting":"Hello, Root!"}}) + test "root data can be set using {module, fun} syntax" do + defmodule TestRootPlugWithMF do + use Plug.Builder + def root_eval(_conn), do: %{greeting: "MF"} + plug GraphQL.Plug.Endpoint, [schema: {TestSchema, :schema}, root_value: {TestRootPlugWithMF, :root_eval}] + end + + success = ~S({"data":{"greeting":"Hello, MF!"}}) + assert_query TestRootPlugWithMF, {:get, "/", query: "{greeting}"}, {200, success} end test "specify schema using {module, fun} syntax" do defmodule TestMFPlug do use Plug.Builder - + plug GraphQL.Plug.Endpoint, schema: {TestSchema, :schema} end success = ~S({"data":{"greeting":"Hello, world!"}}) From 58f489b4e798f36106d91b4f78d0e73db4dc5fbb Mon Sep 17 00:00:00 2001 From: Aaron Weiker Date: Tue, 19 Jan 2016 05:21:11 -0800 Subject: [PATCH 4/5] Checking for the arity of the function reference and also matching easier --- lib/graphql/plug/endpoint.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/graphql/plug/endpoint.ex b/lib/graphql/plug/endpoint.ex index 68a4442..f9e8fb1 100644 --- a/lib/graphql/plug/endpoint.ex +++ b/lib/graphql/plug/endpoint.ex @@ -70,11 +70,11 @@ defmodule GraphQL.Plug.Endpoint do apply(mod, func, [conn]) end - defp evaluate_root_value(conn, root_value) when is_function(root_value) do + defp evaluate_root_value(conn, root_value) when is_function(root_value, 1) do apply(root_value, [conn]) end - defp evaluate_root_value(_, root_value) when is_nil(root_value) do + defp evaluate_root_value(_, nil) do %{} end From 2191aa37fe28cdcd8d6104cdb4419f32ccb03e20 Mon Sep 17 00:00:00 2001 From: Aaron Weiker Date: Tue, 19 Jan 2016 05:58:23 -0800 Subject: [PATCH 5/5] Reordering maps to make schema first --- lib/graphql/plug.ex | 2 +- lib/graphql/plug/endpoint.ex | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/graphql/plug.ex b/lib/graphql/plug.ex index 1e2e35c..00069c7 100644 --- a/lib/graphql/plug.ex +++ b/lib/graphql/plug.ex @@ -16,7 +16,7 @@ defmodule GraphQL.Plug do s -> s end root_value = Keyword.get(opts, :root_value, %{}) - %{root_value: root_value, schema: schema} + %{:schema => schema, :root_value => root_value} end def call(conn, opts) do diff --git a/lib/graphql/plug/endpoint.ex b/lib/graphql/plug/endpoint.ex index f9e8fb1..ee0cfec 100644 --- a/lib/graphql/plug/endpoint.ex +++ b/lib/graphql/plug/endpoint.ex @@ -10,11 +10,11 @@ defmodule GraphQL.Plug.Endpoint do s -> s end root_value = Keyword.get(opts, :root_value, %{}) - %{root_value: root_value, schema: schema} + %{:schema => schema, :root_value => root_value} end def call(%Conn{method: m} = conn, opts) when m in ["GET", "POST"] do - %{root_value: root_value, schema: schema} = conn.assigns[:graphql_options] || opts + %{:schema => schema, :root_value => root_value} = conn.assigns[:graphql_options] || opts query = query(conn) evaluated_root_value = evaluate_root_value(conn, root_value) @@ -51,7 +51,6 @@ defmodule GraphQL.Plug.Endpoint do end defp execute(conn, schema, root_value, query) do - case GraphQL.execute(schema, query, root_value) do {:ok, data} -> case Poison.encode(%{data: data}) do @@ -70,8 +69,8 @@ defmodule GraphQL.Plug.Endpoint do apply(mod, func, [conn]) end - defp evaluate_root_value(conn, root_value) when is_function(root_value, 1) do - apply(root_value, [conn]) + defp evaluate_root_value(conn, fn_root_value) when is_function(fn_root_value, 1) do + apply(fn_root_value, [conn]) end defp evaluate_root_value(_, nil) do