GraphQL - 如果父返回类型是对象列表,则模式拼接上的模式委派不起作用
Posted
技术标签:
【中文标题】GraphQL - 如果父返回类型是对象列表,则模式拼接上的模式委派不起作用【英文标题】:GraphQL - Schema Delegation on Schema Stitching is not working if the Parent return type is a list of Objects 【发布时间】:2018-12-24 04:34:00 【问题描述】:我有一个包含 imageId 的 Publication 对象,我想用它来创建架构委托并加载整个对象。
发布类型定义为:
const PublicationType = new GraphQLObjectType(
name: 'Publication',
description: 'Publication Type',
fields: () => (
id:
type: GraphQLID
,
callToAction:
type: CallToActionType
,
userId:
type: GraphQLID
,
groupId:
type: GraphQLID
,
instruction:
type: InstructionType
,
customizedTitle:
type: GraphQLString
,
content:
type: GraphQLString
,
activityType:
type: ActivityType
,
creationTool:
type: CreationTool
,
gift:
type: GiftType
,
imageId:
type: GraphQLInt
,
thumbnailId:
type: GraphQLInt
,
createdAt:
type: GraphQLInt
,
updatedAt:
type: GraphQLInt
)
);
媒体类型定义为:
const MediaType = new GraphQLObjectType(
name: 'Media',
description: 'Media Object',
fields: () => (
id:
type: GraphQLInt
,
resource:
type: GraphQLString
,
metadata:
type: MetadataType
,
discr:
type: GraphQLString
)
);
其中 MetadataType 是代码中定义的另一种类型。
这 2 个对象通过这些查询公开:
this._schema = new GraphQLObjectType(
name: 'Query',
description: 'Wall Query',
fields: () => (
getGroupPublications:
type: new GraphQLList(PublicationType),
args:
groupId: type: new GraphQLNonNull(GraphQLInt),
from: type: new GraphQLNonNull(GraphQLInt),
to: type: new GraphQLNonNull(GraphQLInt),
,
resolve: (root, args, context) => PublicationResolver.groupPublications(context)
),
);
和
this._schema = new GraphQLObjectType(
name: 'Query',
description: 'Media Query',
fields: () => (
getMedia:
type: MediaType,
args:
mediaId: type: new GraphQLNonNull(GraphQLInt)
,
resolve: (root, args, context) => MediaResolver.mediaLoader(context).load(args.mediaId)
),
);
现在我尝试将定义的所有模式合并到一个模式中,并添加一个委托来加载类型 Media 而不是 ImageID,因此下一个类代表我将公开的主要模式:
import mergeSchemas from 'graphql-tools';
// other imports ...
class Services
private static _instance: Services;
private _wall: PublicationService;
private _media: MediaService;
private constructor()
this._media = new MediaService();
this._wall = new PublicationService();
public static Instance()
return this._instance || (this._instance = new this())
public MainSchema = async () => Promise.all([this._publication.schema, this._media.schema])
.then(args =>
const publicationSchema = args[0];
const mediaSchema = args[1];
const linkSchemaDefs = `
extend type Publication
image: Media
thumbnail: Media
`;
return mergeSchemas(
schemas: [publicationSchema, mediaSchema, linkSchemaDefs],
resolvers:
Publication:
image:
fragment: `... on Publication imageId `,
resolve(parent, args, context, info)
let mediaId = (parent.imageId === parseInt(parent.imageId, 10)) ? parent.imageId : 0;
return info.mergeInfo.delegateToSchema(
schema: mediaSchema,
operation: 'query',
fieldName: 'getMedia',
args:
mediaId: mediaId,
,
context,
info
)
,
thumbnail:
fragment: 'fragment PublicationThumbnailFragment on Publication thumbnailId ',
resolve(parent, args, context, info)
let mediaId = (parent.thumbnailId === parseInt(parent.thumbnailId, 10)) ? parent.thumbnailId : 0;
return info.mergeInfo.delegateToSchema(
schema: mediaSchema,
operation: 'query',
fieldName: 'getMedia',
args:
mediaId: mediaId,
,
context,
info
)
,
,
,
);
)
.catch(error => Logger.Instance().error(
errorName: 'SchemaStitchingError',
logName: 'GraphQL Schema Stitching Error',
cause: error,
message: [`Services GraphQl Schema stitching rejected`],
)
);
export Services
主架构将使用 graphqlExpress 服务器向最终用户公开 但是,我可以在架构定义中看到扩展类型。
但是当我尝试使用定义为的查询查询媒体类型的字段图像时
query
getGroupPublications(groupId:2, from: 1531180800,to: 1532276998)
id
imageId
image
resource
createdAt
查询将直接命中 getGroupPublications 出版物,而不考虑 mergeSchema,我收到此错误:
errors:
[ Cannot query field "image" on type "Publication". Did you mean "imageId"?
GraphQL request (5:3)
4: imageId
5: image
^
6: resource
at Object.Field (/home/docker/workspace/api-gateway/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:65:31)
at Object.enter (/home/docker/workspace/api-gateway/node_modules/graphql/language/visitor.js:324:29)
at Object.enter (/home/docker/workspace/api-gateway/node_modules/graphql/language/visitor.js:366:25)
at visit (/home/docker/workspace/api-gateway/node_modules/graphql/language/visitor.js:254:26)
at visitUsingRules (/home/docker/workspace/api-gateway/node_modules/graphql/validation/validate.js:74:22)
at validate (/home/docker/workspace/api-gateway/node_modules/graphql/validation/validate.js:59:10)
at graphqlImpl (/home/docker/workspace/api-gateway/node_modules/graphql/graphql.js:106:50)
at /home/docker/workspace/api-gateway/node_modules/graphql/graphql.js:66:223
at new Promise ()
at Object.graphql (/home/docker/workspace/api-gateway/node_modules/graphql/graphql.js:63:10)
message: 'Cannot query field "image" on type "Publication". Did you mean "imageId"?',
locations: [Array],
path: undefined ]
但是如果我在没有字段图像的情况下运行我的查询,它可以正常工作
query
getGroupPublications(groupId:1, from: 1531180800,to: 1532276998)
id
imageId
【问题讨论】:
【参考方案1】:我遇到的问题是由于将完整的 Query 传递给远程架构,MergeSchema Resolver 只有在远程架构返回结果后才会执行。
所以在 getGroupPublications 解析器PublicationResolver.groupPublications(context)
中,我替换了通过扩展类型添加的字段。
let queryString = context.req.body.query;
queryString = queryString.replace(/image[\s\r\n]*?[^]*/gm, "");
queryString = queryString.replace(/thumbnail[\s\r\n]*?[^]*/gm, "");
return graphql(schema, queryString,
null,
context,
context.req.body.variables)
【讨论】:
以上是关于GraphQL - 如果父返回类型是对象列表,则模式拼接上的模式委派不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Graphql 中返回 JSON 对象并定义 JSON 类型
如何为嵌套对象或同一父对象中的对象列表定义 GraphQLObjectType
GraphQL SDL(aws appsync)中的“不能为不可为空的类型返回 null:父“消息”(/getMessages/sendBy)中的“人”