GraphQL: Можете ли вы изменить результаты запроса? - PullRequest
0 голосов
/ 14 сентября 2018

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

Одной из приятных особенностей GraphQL является то, что он позволяет выполнять гибкие запросы. Например, если я хочу найти все comments на всех posts каждого user в конкретном forum, тогда я могу сделать запрос

query{
  findForum(id:7){
    users{
      posts{
        comments{
          content
        }
      }
    }
  }
} 

это здорово. Часто вы хотите собрать данные с целью их изменения . Так что в этом случае, может быть, я не хочу получать все эти комментарии, а вместо этого я хочу удалить их. Наивным предложением является реализация поля deleteComment для типа comment, которое изменяет объект, для которого оно вызывается. Это плохо , потому что запрос помечен как query, поэтому он не должен изменять данные.

Поскольку мы мутируем данные, мы обязательно должны пометить это как mutation. Но затем мы теряем способность делать запрос, который хотели сделать, потому что findForum - это поле запроса, а не поле мутации. Способом этого может быть переопределение всех полей запроса, которые вам нужны внутри типа мутации. Это, очевидно, не очень хорошая идея, потому что вы повторяете много кода, а также делаете функциональность для query строгим подмножеством из mutation.

Теперь, что я считаю «обычным» решением, это создать поле мутации, которое выполняет эту работу и ничего больше. Таким образом, вы определяете поле мутации deleteAllUserPostCommentsByForum, которое принимает аргумент, и реализуете его очевидным образом. Но теперь вы потеряли гибкость! Если вместо этого вы решите, что хотите найти user явно, и удалите все их сообщения, или если вы хотите удалить только некоторые их сообщений, вам нужно совершенно новое поле мутации. Это похоже на то, что мне показалось полезным для GraphQL по сравнению с REST.

Итак, есть ли хороший способ избежать этих проблем одновременно?

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

ИМХО вы теряете много косвенных аспектов.

Попытка создать «гибкий» запрос может привести к крайне неоптимизированным действиям сервера.

Запросы решаются структурно, уровень за уровнем, что может привести к обработке большого количества ненужных данных (высокая загрузка памяти).Он не может быть оптимизирован на нижних уровнях (например, на сервере sql) - это приведет к наивной реализации (обработке), например, к множеству «запущенных вручную» SQL-запросов или к еще одному сложному запросу с условиями.

В этом случае серверу вообще не нужны все пользователи, в то время как пост / комментарий пользователя обычно содержат поле user_id (и идентификаторы форума / темы / сообщения) - его можно обрабатывать непосредственно на одной таблице (с помощьюприсоединяемые посты).Вам не нужно, чтобы вся структура влияла только на некоторые элементы.

Реальная мощь и гибкость graphQL возложены на средства распознавания.

Обратите внимание, что удалениевсе или только некоторые комментарии могут быть реализованы совершенно по-разному.Resolver может выбрать лучший способ (по параметрам, как написал Даниэль), но для простоты (удобочитаемости API) было бы лучше иметь отдельные мутации.

0 голосов
/ 14 сентября 2018

Единственная реальная разница между запросами и мутациями заключается в том, что если одна операция включает в себя несколько мутаций, они разрешаются последовательно (по одной за раз), а не одновременно. Запросы и все остальные поля разрешаются одновременно. Это означает, что для такой операции:

mutation myOperation {
  editComment(id: 1, body: "Hello!")
  deleteComment(id: 1)
}

Мутация editComment разрешится до мутации deleteComment. Если бы эти операции были запросами, они выполнялись бы одновременно. Аналогично, подумайте, есть ли у вас мутация, которая возвращает объект, например:

mutation myOperation {
  deleteComment(id: 1) {
    id
    name
  }
}

В этом случае поля id и name также разрешаются одновременно (поскольку, даже если они возвращаются как часть мутации, сами поля не являются мутациями) .

Эта разница в поведении между запросами и мутациями подчеркивает, почему по соглашению мы определяем одну мутацию для каждой операции и избегаем "вложенных" мутаций, как предполагает ваш вопрос.

Ключ к тому, чтобы сделать ваши мутации более гибкими, заключается в том, как впоследствии вы вводите входные данные для своей мутации, как вы обрабатываете эти входные данные внутри вашего резольвера. Вместо того, чтобы делать мутацию deleteAllUserPostCommentsByForum, просто сделайте мутацию deleteComments, которая принимает более надежный InputType, например:

input DeleteCommentsInput {
  forumId: ID
  userId: ID
}

Тогда вашему преобразователю просто нужно обработать любую комбинацию полей ввода, которые могут быть переданы. Если вы используете db, этот тип ввода очень легко преобразуется в предложение WHERE. Если вы понимаете, что вам нужны дополнительные функции, например, удаление комментариев до или после определенной даты, вы можете добавить эти поля в ваш тип ввода и соответственно изменить свой преобразователь - не нужно создавать новую мутацию.

На самом деле вы можете обрабатывать создание и редактирование одинаково и делать вещи немного СУХИМ. Например, ваша схема может выглядеть так:

type Mutation {
  createOrUpdateComment(comment: CommentInput)
}

input CommentInput {
  id: ID
  userId: ID
  body: String
}

Ваш распознаватель может затем проверить, был ли включен идентификатор - если это так, то он обрабатывает операцию как обновление, в противном случае он обрабатывает операцию как вставку. Конечно, использование ненулевых значений в этом случае может быть сложным (userId может потребоваться для создания, но не для обновления), поэтому есть что сказать, чтобы иметь отдельные типы ввода для каждого вида операции. Однако, надеюсь, это все еще иллюстрирует, как вы можете использовать типы ввода, чтобы сделать ваши мутации более гибкими.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...