如何在HotChocolate中检测GraphQL查询请求字段以优化数据获取?
问题描述
我有一个包含两个字段的GraphQL查询,这两个字段分别来自不同的慢数据源,其中一个或两个字段都可能返回错误(示例中用null表示)。当前逻辑是:若一个或两个字段非空,则返回可用值;若两者均为null,则抛出GraphQL错误,实现代码如下:
[ExtendObjectType(OperationTypeNames.Query)] public class FooQuery { [GraphQLName("searchFoo")] public async Task<Foo> SearchFoo(FooRequest request) { var foo = new Foo { Bar = GetBar(), // 慢操作,可能返回null Baz = GetBaz() // 慢操作,可能返回null }; if (foo.Bar == null && foo.Baz == null) { throw new GraphQLException(...); } return foo; } }
但存在用户仅关注Bar字段、未在请求中包含Baz的情况。我想知道是否可以检测请求的字段,从而跳过Baz的处理流程?
我清楚这么做的副作用:如果Bar返回错误,即使Baz有可用数据,整个查询也会返回错误。但已有客户端调用该查询,我不想拆分为独立查询,因为这需要修改客户端代码,而我无法控制客户端。
解决方案
当然可以实现,利用GraphQL的解析上下文就能拿到客户端实际请求的字段,然后针对性跳过未请求的慢操作。从你的代码来看用的是Hot Chocolate框架,具体实现步骤如下:
- 在查询方法中注入
IResolverContext参数,通过它获取当前请求的字段列表。 - 只对请求中存在的字段执行对应的慢数据源调用。
- 调整空值判断逻辑,只检查被请求的字段是否全部为
null,再决定是否抛出错误。
修改后的代码示例:
[ExtendObjectType(OperationTypeNames.Query)] public class FooQuery { [GraphQLName("searchFoo")] public async Task<Foo> SearchFoo(FooRequest request, IResolverContext context) { var foo = new Foo(); // 获取客户端实际请求的字段名称 var requestedFields = context.SelectedFields.Select(f => f.Name).ToList(); // 只处理被请求的字段,跳过未请求的慢操作 if (requestedFields.Contains("bar")) { foo.Bar = await GetBarAsync(); } if (requestedFields.Contains("baz")) { foo.Baz = await GetBazAsync(); } // 检查所有被请求的字段是否都为null var allRequestedNull = requestedFields.All(field => { return field switch { "bar" => foo.Bar == null, "baz" => foo.Baz == null, _ => true }; }); if (allRequestedNull) { throw new GraphQLException(new Error("请求的字段无有效数据")); } return foo; } }
关键点说明
context.SelectedFields会返回客户端本次查询中明确请求的字段,不会包含未提及的字段,所以可以精准判断哪些操作需要执行。- 空值判断逻辑只针对被请求的字段,避免因为未请求的字段默认
null而误抛异常。 - 这种改动完全兼容现有客户端:如果客户端还是请求完整的
Bar和Baz,逻辑和之前完全一致;如果只请求其中一个字段,自动跳过另一个慢操作,提升查询性能。
内容的提问来源于stack exchange,提问作者thelem
相关产品推荐
相关产品推荐

