Apollo federation with graphql java kickstart giving runtime error while executing query

33 Views Asked by At

I have couple of existing backend services exporting graphql data for 'accounts' & 'billing'. These services have implemented graphql using graphql-java-kickstart (without springboot). I want to use apollo federation router on top of these services.

Is it possible to use apollo-federation-jvm with graphql-java-kickstart? I see most of the examples showing schema federation are springboot based.

So far i have implemented following and i am able to get the apollo router running with federated schema, however, when i am executing a query then getting below error:

"message": "Variable 'representations' has an invalid value: Variable 'representations' has coerced Null value for NonNull type '[_Any!]!'",

This error is happening for following query while fetching billing for an account:

query($representations:[_Any!]!){_entities(representations:$representations){...on AccountsItem{billing{accountNumber billingDetails{lastBillAmount}}}}}

Here are schemas for accounts and billing:

Accounts:

 type Query {
  accounts: [AccountsItem!]!
  searchAccounts(filter: AccountFilter!): [AccountsItem!]
}

input AccountFilter {
    accountAlias: String    
}

"AccountOverview for account list call"
type AccountsItem @key(fields: "alias"){
    accountNumber: String
    alias: String
    status: String
    cbpid: String
    accountTypeNumber: String
    autoPayPromoEligInd: String
    
}

Billing:

 type Query {
  billing(accountAlias: String!): Billing!
}

type AccountsItem @key(fields: "alias") @extends {
    alias: String @external
    billing: Billing
}

type Billing {
    accountNumber: String
    billingDetails: BillingDetails
}

type BillingDetails{
    billType: String
    currentBalance: String
    lastBillAmount: String
}

Below code is for schema transformation:

private static DataFetcher<?> getDataFetcher(GraphQLResolver<?>[] resolvers) {
DataFetcher<?> entityDataFetcher = env -> {
    List<Map<String, Object>> argument = env.getArgument(_Entity.argumentName);
    return argument.stream()
            .map(reference -> {
                if ("AccountsItem".equals(reference.get("__typename"))) {
                    return new AccountsItem((String)reference.get("alias"));
                } else if ("billing".equals(reference.get("__typename"))) {
                    return ((BillingResolver)resolvers[0]).billing((String)reference.get("alias"), env);
                }
                return null;
            })
            .collect(Collectors.toList());
};
return entityDataFetcher;

}

@Bean
public GraphQL graphQL(GraphQLResolver<?>[] resolvers) {
    final String originalSDL = readResource("graphql/schema.graphqls");

    DataFetcher<?> entityDataFetcher = getDataFetcher(resolvers);

    GraphQLSchema federatedSchema = Federation.transform(originalSDL, getRuntimeWiring(entityDataFetcher))
            .fetchEntities(entityDataFetcher)
            .resolveEntityType(env -> {
                final Object src = env.getObject();
                if (src instanceof AccountsItem) {
                    return env.getSchema().getObjectType("AccountsItem");
                }
                return null;
                    }
            )
            .build();
    return GraphQL.newGraphQL(federatedSchema).build();
}

private static RuntimeWiring getRuntimeWiring(DataFetcher<?> entityDataFetcher){
    return RuntimeWiring.newRuntimeWiring()
            .type("AccountsItem",typeWiring -> typeWiring
                    .dataFetcher("billing", entityDataFetcher))
            .type("Query",typeWiring -> typeWiring
                    .dataFetcher("billing", entityDataFetcher))
            .build();
}
1

There are 1 best solutions below

0
On

I found the problem with my code. I was not setting 'variables' passed by apollo federation in graphql request in ExecutionInput in below code:

 public ExecutionResult executeQuery (GraphQLBody graphQLBody) {

    ExecutionInput.Builder builder = ExecutionInput.newExecutionInput().query(graphQLBody.getQuery());

    //Below code was missing
    if(graphQLBody.getVariables() != null) {
        builder.variables((Map<String, Object>) graphQLBody.getVariables());
    }
    ExecutionInput executionInput = builder.build();

    ExecutionResult executionResult = graphQL.execute(executionInput);

    return executionResult;
}