Apollo联邦中继承的内部GraphQL实体解析为null问题求助
Apollo联邦+Graphene内部Schema无法解析关联实体问题
场景说明
使用Django+Graphene+graphene-federation搭建Apollo联邦,整合car-service和race-service两个GraphQL服务,每个服务提供/internal/graphql/和/external/graphql/两个端点。内部Schema的类型继承自外部类型(如CarTypeInternal继承CarTypeExternal),但内部API查询时关联的车辆实体无法被解析。
代码片段
通用urls.py
urlpatterns = [ path( "internal/graphql/", csrf_exempt( GraphQLView.as_view( graphiql=True, schema=internal_schema, ) ), ), path( "external/graphql/", csrf_exempt( GraphQLView.as_view( graphiql=True, schema=external_schema, ) ), ), ]
car-service external_schema.py
@key(fields="uuid") class CarTypeExternal(django_filters.DjangoObjectType): class Meta: model = models.Car interfaces = (graphene.relay.Node,) def __resolve_reference(self, info, **kwargs): query_params = { "owner_uuid": get_user_by_token(info.context), "uuid": self.uuid } try: return models.Car.objects.filter(**query_params).first() except models.Car.DoesNotExist: return None
car-service internal_schema.py
@key(fields="uuid") class CarTypeInternal(external_schema.CarTypeExternal): class Meta: model = models.Car interfaces = (graphene.relay.Node,) def __resolve_reference(self, info, **kwargs): query_params = { "uuid": self.uuid } try: return models.Car.objects.filter(**query_params).first() except models.Car.DoesNotExist: return None
race-service external_schema.py
@extend(fields="uuid") class CarTypeExternal(graphene.ObjectType): uuid = external(graphene.UUID(required=True)) class RaceTypeExternal(django_filters.DjangoObjectType): cars = graphene.List(CarTypeExternal) class Meta: model = models.Race interfaces = (graphene.relay.Node,) def resolve_cars(self, info, **kwargs): cars = [] for race_car in models.RaceCar.objects.filter(race__uuid=self.uuid): if race_car.car_uuid is not None: cars.append( CarTypeExternal( uuid=race_car.car_uuid ) ) return cars class Query(graphene.ObjectType): race = graphene.Field( RaceTypeExternal, uuid=graphene.UUID(required=True), ) @staticmethod def resolve_race(self, info, uuid): return models.Race.objects.get( uuid=uuid, )
race-service internal_schema.py
@extend(fields="uuid") class CarTypeInternal(graphene.ObjectType): uuid = external(graphene.UUID(required=True)) class RaceTypeInternal(RaceTypeExternal): cars = graphene.List(CarTypeInternal) class Meta: model = models.Race interfaces = (graphene.relay.Node,) def resolve_cars(self, info, **kwargs): cars = [] for race_car in models.RaceCar.objects.filter(race__uuid=self.uuid): if race_car.car_uuid is not None: cars.append( CarTypeInternal( uuid=race_car.car_uuid ) ) return cars class Query(graphene.ObjectType): race = graphene.Field( RaceTypeInternal, uuid=graphene.UUID(required=True), ) @staticmethod def resolve_race(self, info, uuid): driver_uuid = get_user_by_token(info.context) return models.Race.objects.get( uuid=uuid, driver_uuid=driver_uuid, )
查询结果
- 外部API查询(正常返回cars列表):
{ "race": { "uuid": "7ac2b50f-5db8-4425-9b59-0a714a028ea0", "name": "Nurburgring", "cars": [{ "uuid": "3ba0c10f-0553-4565-a208-2c45d23f9145", "name": "Audi" }, { "uuid": "c6532341-b521-4c59-8536-af06d47e7b2a", "name": "BMW" } ] } }
- 内部API查询同一场race(cars字段为null):
{ "race": { "uuid": "7ac2b50f-5db8-4425-9b59-0a714a028ea0", "name": "Nurburgring", "cars": null } }
- 内部API查询无关联车辆的race(cars字段为[]):
{ "race": { "uuid": "b92098f7-2d2d-4f6d-a538-1f74f83fce27", "name": "Car track", "cars": [] } }
问题分析与修复方案
1. 修复代码笔误
race-service的resolve_cars方法原代码返回未定义的analysis_runs变量,属于明显笔误,修正为返回构造好的cars列表。这个错误直接导致有车辆关联时返回值异常,修正后可解决null问题。
2. 统一联邦实体标识
race-service内部的CarTypeInternal需要和car-service内部的CarTypeInternal使用一致的实体名称,避免联邦无法识别为同一实体。可通过@extend装饰器显式指定name参数:
@extend(fields="uuid", name="Car") class CarTypeInternal(graphene.ObjectType): uuid = external(graphene.UUID(required=True))
3. 配置网关识别内部服务端点
Apollo网关需单独配置内部服务的端点,确保内部Schema被纳入联邦。示例配置:
serviceList: - name: "car-service-internal" url: "http://car-service/internal/graphql/" - name: "race-service-internal" url: "http://race-service/internal/graphql/"
4. 验证内部Schema的实体注册
确保car-service的内部Schema正确注册CarTypeInternal并生成联邦Schema:
# car-service internal_schema.py 末尾 schema = build_schema(Query, types=[CarTypeInternal])
5. 权限与数据排查
检查内部API的resolve_race方法中,当前请求用户是否拥有目标race的权限;同时单独调用car-service内部端点,确认关联车辆能被正常返回。
内容的提问来源于stack exchange,提问作者Jacu
相关产品推荐
相关产品推荐

