Определение мутаций в GraphQL через поля: это плохая практика? - PullRequest
0 голосов
/ 13 сентября 2018

Предположим, у вас есть тип user, а у user много posts.Затем представьте, что вы хотите найти пользователя и удалите все его сообщения.Один из способов сделать это - реализовать следующее поле mutation:

field deleteAllPosts, types[Types::PostType] do
  argument :user_id, types.String

  resolve -> (obj,args,ctx){ 
    posts = Posts.where(user_id:args[:user_id])
    posts.each{|post| post.destroy}
  }
end

Тогда запрос

mutation {
  deleteAllPosts(user_id:1)
}

удалит все сообщения пользователя с идентификатором 1.

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

Идея состоит в том, чтобы вместо поля PostType поставить поле deletePost и поле findUser для мутации (обычно это поле запроса).Предполагая, что очевидно, как эти поля будут определены, я бы тогда сделал запрос

mutation{
  findUser(id:1){
    posts{
      deletePost{
      id
      }
    }
  }
}

Это плохая идея?

Редактировать в ответ на обратную связь : Меня беспокоит то, что пользователь может в принципе сделать выбор deletePost внутризапрос.Но мне хочется сказать, что это «их вина».Я бы хотел бы сказать "этот выбор может быть сделан только если он находится внутри запроса на мутацию", но я не думаю, что это возможно в GraphQL.

Чтобы избежать проблемы XY, вот почему я стремлюсь использовать эту идею, а не исходную.Это чувствует себя более выразительным (иначе говоря, это чувствует себя менее избыточным).Предположим, что через некоторое время вы решите, что хотите удалить все posts для тех users, принадлежащих определенному group.Тогда в том, что я называю «соглашением», вы должны создать совершенно новое поле мутации:

field deleteAllPostsInGroup, types[Types::PostType] do
  argument :group_id, types.String

  resolve -> (obj,args,ctx){ 
    posts = Group.find_by(args[:group_id]).users.map{|u| u.posts}.flatten
    posts.each{|post| post.destroy}
  }
end

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

mutation{
  findGroup(id:1){
    users{
      posts{
        deletePost{
        id
        }
      }
    }
  }
}

Я полагаю, что на самом деле я пытаюсь использовать запрос to найдите некоторые данные, а затем измените найденные данные .Я не знаю, как это сделать в GraphQL.

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

1 Ответ

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

Это в основном проблема качества кода, и она похожа на вопрос о сути принципа СУХОЙ или инкапсуляции.

Цитата из https://graphql.org/learn/queries/ гласит:

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

Это хорошее соглашение, поскольку оно упрощает обслуживание, тестирование и отладку.Побочные эффекты, преднамеренные или нет, могут быть очень трудно отследить и понять.Особенно, если они есть в запросах GraphQL, которые могут быть сколь угодно большими и сложными.Ничто не мешает вам запрашивать и изменять один и тот же объект и его братьев и сестер в одно и то же время, и выполнять это несколько раз в одном запросе путем простого вложения.Очень легко ошибиться.

Даже если вы это сделаете, это ухудшит читабельность кода и удобство обслуживания.Например, если вы знали, что только ваши мутации когда-либо изменяли данные, а запросы не влияли на них, вы бы сразу знали, с чего начать поиск реализации определенного поведения.Также намного проще рассуждать о том, как ваша программа работает в целом.

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

И последнее, но не обязательно самое важное: придерживаться соглашений полезно, если вам когда-нибудь понадобится передать свою работу кому-то другому.

Короче говоря, этовсе о том, чтобы облегчить себе и другим жизнь в будущем.


РЕДАКТИРОВАТЬ

ОК, поэтому я вижу, куда вы идете с этим - вы хотитечтобы придать мутациям гибкость запроса GraphQL.Конечно, этот конкретный пример будет работать.Не идти этим путем будет только о будущем .Нет смысла обсуждать это, если deletePost - единственная операция, которую вы когда-либо определите.

Если это не так, то что, если вы хотите удалить, скажем, 5 конкретных сообщений пользователя?Не могли бы вы дать дополнительные параметры findGroup, а затем передать их в дерево?Но тогда почему метод findGroup должен знать, что вы будете делать с его результатами?Такой вид не поддается идее самого гибкого запроса.Что делать, если вы также хотели выполнять мутации для пользователей?Дополнительные параметры для findGroup?Что если пользователей и сообщений можно запрашивать по-разному, например, пользователей по доменам, сообщений по категориям и т. Д.?Определить там те же параметры?Как бы вы обеспечили, чтобы с каждой операцией (особенно если вы выполняете несколько из них одновременно) все реляционные ссылки были правильно удалены в вашей базе данных?Вы должны представить себе каждую возможную комбинацию запросов и запросов-мутаций и код для них соответствующим образом.Поскольку размер запроса не ограничен, это может оказаться очень трудным для выполнения.И даже если цель отдельной мутации запроса (deletePost) ясна и ее легко понять, общий запрос не будет.Быстро ваши запросы станут слишком сложными для понимания даже для вас, и вы, вероятно, начнете разбивать их на более мелкие, которые будут выполнять только определенные мутации.Таким образом, вы вернетесь к исходному соглашению, но к более сложной версии.Вы, вероятно, также в конечном итоге определите некоторые регулярные мутации.Как бы вы обновили или добавили сообщения, например?Это распространит вашу логику повсюду.

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

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

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