Apollo Federation 从 ID 解析数组
Posted
技术标签:
【中文标题】Apollo Federation 从 ID 解析数组【英文标题】:Apollo Federation Resolve Array from IDs 【发布时间】:2021-01-13 16:15:33 【问题描述】:我使用 MongoDB 作为我的联合 Apollo GraphQL API 的数据库。
(我的代码在 TypeScript 中)
我为Post
解析器对象创建了一个__resolveReference
方法,当我从user service
调用它时,它工作正常,如下所示:
User:
...
firstPost(user: any)
return __typename: "Post", _id: user.firstPost ;
,
...
但是,当我在数组上调用它时,它不起作用。以下是我的称呼:
User:
...
posts(user: any)
user.posts.map((x: any) =>
return __typename: "Post", _id: x ;
);
,
...
帖子__resolveReference
代码如下:
Post:
...
async __resolveReference(reference: any, db : any)
console.log(reference);
console.log(reference._id);
try
let r = (await db
.collection("posts")
.findOne( _id: new ObjectID(reference._id) )) as Post;
console.log(r.content);
return r;
catch (err)
console.log(err.stack);
,
...
我知道从posts
解析器对User
对象调用时__resolveReference
没有被“命中”,因为console.log()
s 没有显示在终端中,同样,仅来自@987654333 @resolver 而不是firstPost
。
我需要一些帮助来让 __resolveReference
为数组工作。
谢谢。
【问题讨论】:
firstPost 和 posts 解析器应该在 Post 服务而不是 User 服务中实现。您应该在 Post 类型上扩展 User 类型以构建引用,如下所示:apollographql.com/docs/federation/#federated-schema-example 【参考方案1】:在 Apollo Federation 中,如果要返回数组,__resolveReference
中的返回数组无法正常工作,解决方案是创建一个新类型。
例如,如果您在一项服务中实现了User
并在另一项服务中发布
User
和 Post
模型的简单表示是这样的:
typescript
-- User Service
type User
id: ID!
email: String!
password: String!
-- Post Service
type Post
id: ID!
content: String!
postedBy: ID!
date: Date
comments: [String]!
Add a reference to Post type
//define a key in Post
type Post @key(fields:"id")
//Add a field on User like
type User
id: ID!
email: String!
password: String!
post: [Post]!
extend type Post @key(fields:"id")
id: ID! @external
此方法无效。
一个解决方案是在Post Service
中创建一个新类型:
type PostList @key(fields: "idUser")
idUser: ID!
posts: [Post]!
PostList :
__resolveReference(reference)
//data is a array of post
let userPost = data.filter((p)=>p.postedBy==reference.idUser)
return idUser: reference.idUser, posts: userPost
在您的User
服务中执行以下操作:
type User
id: ID!
email: String!
password: String!
posts: PostList
extend type PostList @key(fields:"idUser")
idUser: ID! @external
in User resolver
User :
posts(_parent)
return __typename: "PostList", idUser: _parent.id
并查看__resolveReference
是否与async/await
函数一起使用。
【讨论】:
如果他们在 post 端没有任何关系怎么办,这最终只会违反关注点分离,看起来不是解决这个问题的正确方法。 :/ 例如,我有一个帖子和一个发布它的频道 Post channels: [Channel] 与频道方面的帖子没有关系,不应该。【参考方案2】:处理此问题的另一种方法是在Post
服务上使用User
类型的extend
。
我在这个例子中使用prisma,你可以使用任何fetch函数来解析你的数据,但是做法是一样的。
邮政服务
const resolvers =
User:
posts: async (root: any) => await prisma.post.findMany( where: userId: root.id ),
,
;
const typeDefs = gql`
type Post
id: ID!
extend type User @key(fields: "id")
id: ID! @external
posts: [Post]!
`
用户服务
const resolvers =
Query:
user: async (_root: any, args: any) => await prisma.user.findUnique( where: id: args.id )
,
User:
__resolveReference: async (root: any) => await prisma.user.findUnique( where: id: root.id ),
,
;
const typeDefs = gql`
type Query
user(id: ID!): User
type User @key(fields: "id")
id: ID!
`
【讨论】:
以上是关于Apollo Federation 从 ID 解析数组的主要内容,如果未能解决你的问题,请参考以下文章
GraphQL Apollo Federation-JVM 中 @extends 类型的解析器问题
如何使用 Apollo Federation 从网关到服务的请求中获取完整的详细信息
Apollo Federation 上的两个微服务之间的突变
使用 apollo-federation 独立构建 GraphQL 服务