GraphQL - 如何区分 Public 和私有字段?

GraphQL - How to distinguish Public from Private fields?

上下文
我有一个 GraphQL API 和一个 NodeJS & Angular 应用程序,带有一个 MongoDB 数据库来保存用户。对于每个用户,都有一个 public 页面,其中包含 public 信息,例如 idusername。用户登录后,会出现一个私人资料页面,其中包含 email.

等扩展信息

仅供参考,我正在使用 jsonwebtoken with accesscontrol 对用户进行身份验证和授权。该信息存储在每个 GraphQL 解析函数的上下文中,因此可以使用识别登录用户所需的任何信息。

我有一个 GraphQL 查询可以像这样检索 public 用户:

query getUserById($id: ID!) {
  getUserById(id: $id) {
    id,
    username
  }
}

我正在考虑检索 public 或私人用户的正确实现。由于 GraphQL 是强类型的,我在想出一个合适的解决方案时遇到了一些麻烦。

问题
如何区分public和私人用户?

注意事项

1.单独查询
因此,其中一种选择是对 public 和私有字段进行单独查询:

public查询

query getUserById($id: ID!) {
  getUserById(id: $id) {
    id,
    username
  }
}

私人查询

query getMe {
  getMe {
    id,
    username,
    email
  }
}

2。使用 GraphQL 接口
我遇到了 this Medium article,它解释了 GraphQL 接口如何用于 return 基于 resolveType 函数的不同类型。所以我会这样做:

query getUser($id: ID!) {
   getUser(id: $id) {
     ... on UserPrivate {
       id,
       username
     }
     ... on UserPublic {
       id,
       username,
       email
     }
   }
}

我还没有找到合适的解决方案,我不确定我目前的任何考虑。

非常感谢任何帮助!

我认为您在这里缺少的是,在 GraphQL 中,您通常想要创建这种深度连接的图形结构。虽然 getUserByIdgetMe 作为入口点工作得很好(而且我认为即使使用接口类型它们仍然是一个好主意),但您很可能会在整个架构中出现用户类型。想象一下热门博客post例子:

type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
}

在这里添加两个作者字段并不是很好。同样,在您的示例中,您可能不知道个人资料页面是您自己的,直到您收到后端的响应(想想 Twitter 个人资料)。

相反,在我看来有两种方法可以考虑:

第一个是界面的想法。您将拥有一个接口,其中包含私有和 public 类型的所有公共字段和具体实现。这里的好处是:如果您只使用公共字段,您甚至不必使用类型匹配:

query getUser($id: ID!) {
   getUser(id: $id) {
     id
     username

     # if you need a private field you can branch off here
     ... on UserPrivate {
       email
     }
   }
}

当它变得更细粒度时(人们分享他们想要公开给 public 的内容,想象一下 Facebook)或者你有很多类型(UserMe、UserFriend、UserStranger)你可能想要考虑 nullable字段代替。如果您无权访问该字段,您将从 API 收到空值。为了减少 null 检查的数量,您可以轻松地将字段捆绑到它们自己的类型中(例如 Address)。

总结:

从 API 点开始,return 可为 null 的字段更容易一些,因为它为您提供了很大的灵活性。与第一个相比,在不破坏更改的情况下发展第二个选项要容易得多。如果您使用静态类型(Typescript、Flow、Scala.js、Reason 等),那么在前端使用接口会更有表现力并且肯定会更有趣。关键字:模式匹配。