GraphQL - 如果父 return 类型是对象列表,则模式拼接的模式委托不起作用
GraphQL - Schema Delegation on Schema Stitching is not working if the Parent return type is a list of Objects
我有一个包含 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 类型,因此下一个 class 代表我将公开的主要模式:
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
}
}
我遇到的问题是由于将完整的查询传递给远程架构,MergeSchema Resolver 将仅在远程架构 returns 结果之后执行。
所以在 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)
我有一个包含 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 类型,因此下一个 class 代表我将公开的主要模式:
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
}
}
我遇到的问题是由于将完整的查询传递给远程架构,MergeSchema Resolver 将仅在远程架构 returns 结果之后执行。
所以在 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)