micronaut に限らず、GraphQL Java を利用していればSpring boot や他のフレームワークでも同じことができます。
また、groovy で書いてますが、Java / kotlin でも同様のことは実装できます。
schema
こんな感じのschema
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
type Query { someExample : ReturnType } union ReturnType = ReturnTypeA | ReturnTypeB type ReturnTypeA { id: ID! name: String } type ReturnTypeB { id: ID! name: String extra: String } |
ReturnType が、ReturnTypeA と、ReturnTypeB の二つのどちらかとなる場合。
Groovy側ソース
GraphQL インスタンスの作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
@Factory @CompileStatic class GraphQLFactory { @Bean @Singleton GraphQL graphQL(ResourceResolver resourceResolver , SomeExampleFetcher someExampleFetcher) { def schemaParser = new SchemaParser() def schemaGenerator = new SchemaGenerator() // Parse the schema. def typeRegistry = new TypeDefinitionRegistry() typeRegistry.merge(schemaParser.parse(new BufferedReader(new InputStreamReader( resourceResolver.getResourceAsStream("classpath:schema.graphqls").get())))) // Unionの型のResolver を作成 TypeResolver typeResolverReturnType = new TypeResolver() { @Override public GraphQLObjectType getType(TypeResolutionEnvironment env) { Object javaObject = env.getObject(); if (javaObject instanceof ReturnTypeAclass) { return env.getSchema().getObjectType("ReturnTypeA"); } else if (javaObject instanceof ReturnTypeBclass) { return env.getSchema().getObjectType("ReturnTypeB"); } } }; // someExample のFetherと、ReturnType の TypeResolver を指定 def runtimeWiring = RuntimeWiring.newRuntimeWiring() .type("Query", {typeWiring -> typeWiring.dataFetcher("someExample", someExampleFetcher)}) .type("ReturnType", {typeWiriing -> typeWiriing.typeResolver(typeResolverReturnType)}) .build() // Create the executable schema. def graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring) // Return the GraphQL bean. return GraphQL.newGraphQL(graphQLSchema).build() } } |
それぞれ、schema に合わせた、クラスを作成
1 2 3 4 5 6 7 8 9 10 11 |
class ReturnTypeAclass { Integer id String name } class ReturnTypeBclass { String id String name String extra } |
最後に、DataFetcher
1 2 3 4 5 6 7 8 9 10 11 |
@Factory @CompileStatic class SomeExampleFetcher implements DataFetcher{ @Override ReturnTypeAclass get(DataFetchingEnvironment environment) throws Exception { // ReturnTypeBclass を返せば、queryの結果もReturnTypeB になる。 return new ReturnTypeAclass(id:1, name: "aaaaa") } } |
実行
以下のクエリで、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
query SomeExample { someExample { ... on ReturnTypeA { name } ... on ReturnTypeB { id } } } |
結果こんな感じ
1 2 3 4 5 6 7 8 9 |
{ "data": { "someExample": { "name": "aaaaa" } } } |