GraphQL查询可空关联字段的非空子字段触发非空报错
GraphQL可空嵌套字段查询报错问题(GQLGen+Apollo)
问题背景
我定义的GraphQL Schema中,Employee类型的lastActivity字段为可空,但客户端查询该字段的嵌套非空字段时,服务端抛出非空约束错误。仅将Activity所有字段改为可空能解决问题,但我只希望lastActivity字段本身可空,不想修改Activity的字段约束。
定义的Schema
type Employee { id: UUID! createdAt: Time! updatedAt: Time! lastActivity: Activity } type Activity { id: UUID! createdAt: Time! updatedAt: Time! } extend type Query { Myself: Employee! }
客户端查询语句
query Myself { Myself { id lastActivity { id action createdAt } organization { id name slug } } }
报错响应
{ "errors": [ { "message": "the requested element is null which the schema does not allow", "path": [ "Myself", "lastActivity", "createdAt" ] } ], "data": { "Myself": { "id": "257d9db3-118e-4728-9e6b-ef28e87b4907", "lastActivity": null, "__typename": "Employee" } } }
问题原因
这是GQLGen的默认校验逻辑导致的:当你查询可空父字段的非空子字段时,即使父字段返回null,GQLGen仍会尝试解析子字段的非空约束,进而抛出错误。虽然GraphQL规范允许父字段为null时子字段返回null,但GQLGen默认开启了严格的非空校验(enforceNonNull: true),会将这种情况判定为违反Schema约束。
解决方案
方案1:修改GQLGen配置(推荐)
在项目的gqlgen.yml配置文件中,全局关闭严格非空校验,或者针对特定字段配置:
# 全局关闭严格非空校验,符合GraphQL规范 enforceNonNull: false # 或者仅针对Employee的lastActivity字段配置(局部生效) models: Employee: fields: lastActivity: nullable: true skipResolver: false # 确保resolver返回null时不触发子字段解析
方案2:在Resolver中手动处理
在Employee类型的LastActivity resolver函数中,当没有对应的Activity数据时,直接返回nil,避免GQLGen触发子字段的解析逻辑:
func (r *employeeResolver) LastActivity(ctx context.Context, obj *model.Employee) (*model.Activity, error) { // 查询数据库或其他数据源获取lastActivity activity, err := r.db.Activity.FindOne(ctx, obj.LastActivityID) if err != nil || activity == nil { // 无数据时直接返回nil,不触发子字段解析 return nil, nil } return activity, nil }
注意事项
不要修改Activity的字段为可空,这会破坏Activity类型本身的数据约束。问题的核心是GQLGen的校验逻辑,而非Activity字段的定义。
内容的提问来源于stack exchange,提问作者Laurent
相关产品推荐
相关产品推荐

