GraphQL - Как отличить публичные поля от приватных?

Контекст
У меня есть GraphQL API и приложение NodeJS & Angular с базой данных MongoDB, в которой содержатся пользователи. Для каждого пользователя есть общедоступная страница с общедоступной информацией, например id и username. Когда пользователь входит в систему, появляется личная страница профиля с расширенной информацией, например email.

Просто для контекста я использую jsonwebtoken с accesscontrol для аутентификации и авторизации пользователя. Информация хранится в контексте каждой функции разрешения GraphQL, поэтому доступно все, что необходимо для идентификации вошедшего в систему пользователя.

У меня есть запрос GraphQL, который извлекает общедоступного пользователя следующим образом:

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

Я пытаюсь придумать правильную реализацию для извлечения публичного или частного пользователя. Поскольку GraphQL строго типизирован, у меня возникли проблемы с поиском правильного решения.

Вопрос
Как провести различие между общедоступным и частным пользователем?

Рекомендации

1. Отдельный запрос
Таким образом, один из вариантов - создать отдельный запрос как для общедоступных, так и для частных полей:

общедоступный запрос

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

частный запрос

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

2. Использование интерфейсов GraphQL
Я наткнулся на этот носитель статья, в которой объясняется, как интерфейсы GraphQL используются для возврата различных типов на основе resolveType функции. Я бы сказал примерно так:

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

Я не нашел подходящего решения, и я не уверен ни в одном из соображений, которые у меня есть.

Любая помощь высоко ценится!


person Nicky    schedule 07.03.2018    source источник


Ответы (1)


Я думаю, что вам здесь не хватает того, что в GraphQL вы обычно хотите создать эту глубоко связанную структуру графа. Хотя getUserById и getMe хорошо работают в качестве точек входа (и я думаю, что они по-прежнему являются отличной идеей даже с учетом типа интерфейса), у вас, скорее всего, будут типы пользователей, появляющиеся повсюду в вашей схеме. Представьте себе популярный пример сообщения в блоге:

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

Добавление двух полей автора здесь не очень хорошо работает. Точно так же в вашем примере вы можете не знать, что страница профиля принадлежит вам, пока не получите ответ от серверной части (подумайте о профилях в Twitter).

Вместо этого, на мой взгляд, можно рассмотреть два метода:

Во-первых, идея интерфейса. У вас будет интерфейс со всеми общими полями и конкретными реализациями для частного и общедоступного типа. Приятная вещь: если вы используете только общие поля, вам даже не нужно использовать сопоставление типов:

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

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

Когда он станет более детализированным (люди делятся тем, что они хотят показать публике, представьте себе Facebook) или у вас будет много типов (UserMe, UserFriend, UserStranger), вы можете вместо этого рассмотреть поля, допускающие значение NULL. Если у вас нет доступа к полю, вы получите null от API. Чтобы уменьшить количество нулевых проверок, вы можете легко объединить поля в их собственные типы (например, Address).

Резюме:

С точки зрения API вернуть поля, допускающие значение NULL, немного проще, потому что это дает вам большую гибкость. Второй вариант намного проще развить без внесения изменений, чем первый. Использование интерфейсов более выразительно и, безусловно, более увлекательно для работы во внешнем интерфейсе, если вы работаете со статическими типами (Typescript, Flow, Scala.js, Reason и т. Д.). Ключевое слово: соответствие шаблону.

person Herku    schedule 07.03.2018
comment
Спасибо, это очень помогает :) - person Nicky; 07.03.2018