GraphQL register new Type wiring with argument to data fetcher

1.9k Views Asked by At

Having a GraphQL schema:

type TypeA {
   id: ID,
   name: String,
   other: TypeC
}

type TypeB {
   id: ID,
   name: String,
   other: TypeC
}

How should I implement TypeC wiring independently from source object type? I know I can do:

RuntimeWiring.newRuntimeWiring()
  .type(TypeRuntimeWiring.newTypeWiring("TypeA")
    .dataFetcher("other", dataFetcher_typeC.get())
  .type(TypeRuntimeWiring.newTypeWiring("TypeB")
    .dataFetcher("other", dataFetcher_typeC.get())
  .build()

but then the data fetcher is dependant on a source object type:

DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
  return dataFetchingEnvironment -> {
    <??> sourceObj = dataFetchingEnvironment.getSource();
    return getObject(sourceObj.someProperty);
  };
}

Given both POJOs (TypeA and TypeB) have reference field to TypeC, how to resolve TypeC field by given reference, not source object?

2

There are 2 best solutions below

0
On

I have actually figured out two possible solutions to the problem:

  1. When defining new wiring, get source object and from it the field. Call dataFetcher method with parameter, like regular java method:
  2. Inside data fetcher get field name from DataFetcherEnvironment. Use reflection to get field from source object

Example #1:

RuntimeWiring.newRuntimeWiring()
  .type(TypeRuntimeWiring.newTypeWiring("TypeA")
    .dataFetcher("other", environment -> {
        TypeA sourceObj = environment.getSource();
        return dataFetcher_typeC.get(sourceObj.other)})
  .type(TypeRuntimeWiring.newTypeWiring("TypeB")
        TypeB sourceObj = environment.getSource();
        return dataFetcher_typeC.get(sourceObj.other)})
  .build()

Example #2:

DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
  return dataFetchingEnvironment -> {
    Field  declaredField = dataFetchingEnvironment.getSource().getClass()
                  .getDeclaredField(dataFetchingEnvironment.getField().getName());
    declaredField.setAccessible(true);

    String value = (String) declaredField.get(dataFetchingEnvironment.getSource());
    return getObject(sourceObj.someProperty);
  };
}

Second option looks better but still unsure if this is correct approach.

0
On

From the documentation here

the dataFetchingEnvironment provides getExecutionStepInfo() method which returns the ExecutionStepInfo object. From there, you can get the parent information.

ExecutionStepInfo executionStepInfo = environment.getExecutionStepInfo();
ExecutionStepInfo parentInfo = executionStepInfo.getParent();
GraphQLObjectType parentType = (GraphQLObjectType) parentInfo.getUnwrappedNonNullType();

// parentType.getName() returns you "TypeA" or "TypeB"