graphql-elixir / plug_graphql

Plug (Phoenix) integration for GraphQL Elixir
Other
126 stars 7 forks source link

Integration with Auth (Guardian) #22

Closed naderhen closed 8 years ago

naderhen commented 8 years ago

I'm attempting to access the currently logged in user during GraphQL resolves. Looking at the pull-request history (specifically #9, it seems I should be able to inject whatever data I need via the root_value so I've defined a module like so:

defmodule MyApp.GraphQLSession do
  def root_eval(_conn) do
    %{conn: _conn}
  end
end

and amended my api pipeline to:

pipeline :api do
    plug :accepts, ["json"]

    plug Guardian.Plug.VerifyHeader
    plug Guardian.Plug.LoadResource

    plug GraphQL.Plug.Endpoint, [schema: {GraphQL.Schema.EctoWorld, :schema}, root_value: &MyApp.GraphQLSession.root_eval/1]
end

scope "/graphql" do
    pipe_through :api

    get  "/ecto", GraphQL.Plug, schema: {GraphQL.Schema.EctoWorld, :schema}
    post "/ecto", GraphQL.Plug, schema: {GraphQL.Schema.EctoWorld, :schema}
end

scope "/api", MyApp do
    pipe_through :api

    ....
    post "/registrations", RegistrationController, :create

    post "/sessions", SessionController, :create
    delete "/sessions", SessionController, :delete

    get "/current_user", CurrentUserController, :show
    ....
end

Note: I'm using Guardian for authentication.

However, whenever I try and hit any endpoint (either via GraphiQL or curl) an exception is raised:

(Plug.Conn.AlreadySentError) the response was already sent

I'm sure I'm missing something fairly simple as I've just started learning Elixir/Phoenix. I was hoping to get any insight into this or perhaps a working example of integrating GraphQL with Guardian.

Please let me know if there is any more information I can provide.

Thanks!

aweiker commented 8 years ago

@naderhen The GraphQL plug should only be forwarded to for certain endpoints using forward, or a combination of get and post. Check out these examples.

The reason you are probably getting an error is because the plugs are stepping on each other. What I'm speculating is that the Guarding plug is forcing a halt on the connection and then the GraphQL plug has already sent back data in the response as you have it getting executed on each request.

In the end you will want something like:

  scope "/graphql" do
    pipe_through :api
    forward "/", GraphQL.Plug.Endpoint, [
                         schema: { GraphQL.Schema.EctoWorld, :schema }, 
                         root_value: {MyApp.GraphQLSession, :root_value} ]
  end

If you are running inside of Phoenix, you should use the {mod, :fun} syntax so that Phoenix can properly do live code reloading.

naderhen commented 8 years ago

Wow, that fixed it. Thanks so much!

joshprice commented 8 years ago

If you only have a single GraphQL endpoint then forward is the preferred approach.

Please post any other questions, we'd love to include some Guardian examples also!