The format to register an Absinthe endpoint in Phoenix is forward "/graphql", MyAppWeb.GraphQL.Plug and you can only forward to a plug once. I’m wondering if there is a way around this.
Some background:
I currently have two schemas. One for public access and one for authenticated “CMS” access. I choose the schema depending on if there is an authenticated user or not.
defmodule MyAppWeb.GraphQL.Plug do
alias MyAppWeb.GraphQL
@guest_schema Absinthe.Plug.init(schema: GraphQL.Public.Schema)
@admin_schema Absinthe.Plug.init(schema: GraphQL.Admin.Schema)
def init(opts), do: opts
def call(conn, _opts) do
case conn.private[:absinthe].context do
%{authenticated_user: _user} -> Absinthe.Plug.call(conn, @admin_schema)
_ -> Absinthe.Plug.call(conn, @guest_schema)
end
end
end
The problem: Through API discovery (graphiql etc.) only the public schema is visible. Is there a way to achieve this through multiple API endpoints or is there a different, preferred approach?
This is how I ended up solving it: I made one schema with all queries. All publicly accessible fields get a published_ prefix so they are easily distinguishable. All admin queries are protected by a RequireAuthentication middleware that checks for an authenticated user and bails if it isn’t there.
There are separate types as well as a published podcast may have different attributes exposed as a nonpublic podcast.
Query definitions look like this:
defmodule MyAppWeb.GraphQL.Schema do
use Absinthe.Schema
# ...
query do
# Public queries
@desc "Get all published podcasts"
field :published_podcasts, list_of(:published_podcast) do
resolve &Public.Resolvers.Directory.list_podcasts/3
end
@desc "Get one published podcast"
field :published_podcast, :published_podcast do
arg :id, non_null(:id)
resolve &Public.Resolvers.Directory.find_podcast/3
end
@desc "Get one published episode"
field :published_episode, :published_episode do
arg :id, non_null(:id)
resolve &Public.Resolvers.Directory.find_episode/3
end
# Admin queries
@desc "Get all podcasts"
field :podcasts, list_of(:podcast) do
middleware Middleware.RequireAuthentication
resolve &Admin.Resolvers.Editor.list_podcasts/3
end
@desc "Get one podcast"
field :podcast, :podcast do
arg :id, non_null(:id)
middleware Middleware.RequireAuthentication
resolve &Admin.Resolvers.Editor.find_podcast/3
end
@desc "Get one episode"
field :episode, :episode do
arg :id, non_null(:id)
middleware Middleware.RequireAuthentication
resolve &Admin.Resolvers.Editor.find_episode/3
end
end
end
I’m having the same issue, and though your solution shall work, it feels like a workaround. This is unfortunate that it is not possible to handle this case properly.