You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Apollo Federation与graphql-java-kickstart执行查询时遇运行时错误

问题

我有两个基于graphql-java-kickstart(非SpringBoot)的后端服务,分别提供accounts和billing的GraphQL数据,希望在其上部署Apollo Federation Router。请问是否可以将apollo-federation-jvm与graphql-java-kickstart结合使用?目前看到的联邦Schema示例多为SpringBoot相关。

我已完成相关实现并成功启动Apollo Router,但执行查询时出现以下错误:
"message": "Variable 'representations' has an invalid value: Variable 'representations' has coerced Null value for NonNull type '[_Any!]!'"

该错误发生在获取账户账单的如下查询中:

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

Accounts服务Schema

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服务Schema

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
}

实现代码

实体数据获取器

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;
}

GraphQL实例构建

@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();
}

请求协助排查该错误原因并解决。


解答

关于apollo-federation-jvm与graphql-java-kickstart的兼容性

完全可以结合使用,两者都是基于graphql-java生态的组件,只要正确处理Schema联邦转换和数据获取逻辑即可,并非只能在SpringBoot环境下使用。

错误原因排查与修复

1. 核心问题定位

错误提示representations变量被强制转换为Null,本质是代码中数据获取器和RuntimeWiring的配置错误,导致服务无法正确处理Apollo Router传递的联邦查询请求,最终返回不符合要求的Null值触发校验错误。

2. 代码中的具体问题

(1)getDataFetcher类型判断错误

Billing服务中扩展的是AccountsItem类型,Apollo Router传递的__typename应为"AccountsItem",但代码中错误判断为"billing",导致匹配失败返回Null。

(2)RuntimeWiring配置错误

将用于处理_entities查询的entityDataFetcher绑定给了AccountsItem的billing字段,该数据获取器的逻辑并不适用于解析单个字段,导致字段解析异常。

(3)resolveEntityType逻辑不完整

缺少对Billing类型的处理,后续可能引发其他类型解析问题。

3. 修复后的代码

修正getDataFetcher(Billing服务)

private static DataFetcher<?> getDataFetcher(GraphQLResolver<?>[] resolvers) {
DataFetcher<?> entityDataFetcher = env -> {
    List<Map<String, Object>> argument = env.getArgument(_Entity.argumentName);
    return argument.stream()
            .map(reference -> {
                // 仅处理AccountsItem类型,因为Billing服务扩展的是该类型
                if ("AccountsItem".equals(reference.get("__typename"))) {
                    AccountsItem item = new AccountsItem();
                    item.setAlias((String) reference.get("alias"));
                    return item;
                }
                return null;
            })
            .collect(Collectors.toList());
};
return entityDataFetcher;
}

修正RuntimeWiring配置

private static RuntimeWiring getRuntimeWiring(GraphQLResolver<?>[] resolvers) {
    BillingResolver billingResolver = (BillingResolver) resolvers[0];
    return RuntimeWiring.newRuntimeWiring()
            // 给AccountsItem的billing字段绑定专属解析器
            .type("AccountsItem", typeWiring -> typeWiring
                    .dataFetcher("billing", env -> {
                        AccountsItem item = env.getSource();
                        return billingResolver.billing(item.getAlias(), env);
                    }))
            // 给Query的billing字段绑定正常解析逻辑
            .type("Query", typeWiring -> typeWiring
                    .dataFetcher("billing", env -> {
                        String accountAlias = env.getArgument("accountAlias");
                        return billingResolver.billing(accountAlias, env);
                    }))
            .build();
}

完善resolveEntityType(可选)

.resolveEntityType(env -> {
    final Object src = env.getObject();
    if (src instanceof AccountsItem) {
        return env.getSchema().getObjectType("AccountsItem");
    }
    if (src instanceof Billing) {
        return env.getSchema().getObjectType("Billing");
    }
    return null;
})

4. 额外检查点

  • 确保Accounts服务的_entities查询能正确返回包含alias的AccountsItem对象。
  • 检查Apollo Router配置,确认它已正确发现两个服务的联邦Schema。
  • 验证联邦查询流程:先从Accounts服务获取AccountsItem,再由Router调用Billing服务关联获取billing数据。

内容的提问来源于stack exchange,提问作者suraj bahl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:32:02