Last active
December 2, 2017 15:06
-
-
Save tlux/765835296ef3e547cd0e232a0c1eed47 to your computer and use it in GitHub Desktop.
GraphQL: Using fragments on interfaces or unions with Absinthe and Apollo. The Mix task basically generates a JSON file from your Absinthe schema that contains mappings of interfaces/unions to the particular implemented types. This file can subsequently be read by your custom Apollo client.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Provides an automated solution for the following issue: | |
// http://dev.apollodata.com/react/initialization.html#fragment-matcher | |
import { | |
ApolloClient, | |
createNetworkInterface, | |
IntrospectionFragmentMatcher | |
} from 'apollo-client' | |
import types from './typemap.json' | |
// Use a custom fragment matcher to tell Apollo how interface and union types | |
// used in fragments resolve to implemented types. | |
const fragmentMatcher = new IntrospectionFragmentMatcher({ | |
introspectionQueryResultData: { | |
__schema: { types } | |
} | |
}) | |
// Define a the GraphQL endpoint. | |
const networkInterface = createNetworkInterface({ | |
uri: '/graphql' | |
}) | |
// Build the Apollo client. | |
export default new ApolloClient({ | |
networkInterface, | |
fragmentMatcher | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Mix.Tasks.Apollo.Gen.Typemap do | |
@moduledoc """ | |
Provides a task to regenerate the fragment-types.json file which provides | |
details about GraphQL interfaces and unions that are used by the Apollo | |
library. | |
""" | |
use Mix.Task | |
alias Absinthe.Schema, as: SchemaUtils | |
alias Absinthe.Type.Interface | |
alias Absinthe.Type.Union | |
# TODO: Replace this with your own Absinthe schema! | |
alias MyApp.Web.Schema | |
@shortdoc "Generates a GraphQL typemap.json file for Apollo" | |
# TODO: Whereever you want your file to be located! | |
@path Path.join(File.cwd!, "./typemap.json") | |
@doc false | |
@spec run([String.t]) :: any | |
def run(_args) do | |
data = for type <- SchemaUtils.types(Schema), | |
type.__struct__ in [Interface, Union] do | |
identifier = type.__reference__.identifier | |
implementations = SchemaUtils.concrete_types(Schema, identifier) | |
kind = case type do | |
%Interface{} -> "INTERFACE" | |
%Union{} -> "UNION" | |
end | |
possible_types = Enum.map(implementations, &%{"name" => &1.name}) | |
%{ | |
"kind" => kind, | |
"name" => type.name, | |
"possibleTypes" => possible_types | |
} | |
end | |
Application.ensure_all_started(:poison) | |
serialized_data = Poison.encode!(data, pretty: true) | |
File.write!(@path, serialized_data) | |
end | |
end |
In order for this to work with unions I had to adapt the code a bit:
def run(_args) do
data =
for type <- SchemaUtils.types(Schema),
type.__struct__ in [Interface, Union] do
# Schema.implementors only supports interface types
implementations = SchemaUtils.concrete_types(Schema, type)
kind = case type do
%Interface{} -> "INTERFACE"
%Union{} -> "UNION"
end
possible_types = Enum.map(implementations, &%{"name" => &1.name})
%{
"kind" => kind,
"name" => type.name,
"possibleTypes" => possible_types
}
end
Application.ensure_all_started(:poison)
serialized_data = Poison.encode!(data, pretty: true)
File.write!(@path, serialized_data)
end
Thanks for the hint! I fixed that in the original code.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
UPDATE:
Please disregard my question below. Everything was working fine, I just made a really dumb mistake and had neglected to export my IntrospectionFragmentMatcher object.
This is fantastic. Thanks for sharing the mix task. Might you be able to share what one of your queries looks like? I'm trying to get a UNION working and am running into some trouble. If I run the query using the Graphiql web based tool it looks like everything comes back as I would expect, but when running the query in my app using Apollo I just get undefined for the query data.