Рубрики
Без рубрики

Остерегайтесь вложенные мутации GraphQL!

«У меня есть хитрый план …» Однажды я ударил на понятие организации мутаций GraphQL с помощью вложенных операций в типе возврата. Идея заключалась в том, что эти операции затем мутируют родительскую организацию. Основная идея была это: входной AddbookInput {isbn: string! Название: Строка! } Вход RemoveBoodInput.

Автор оригинала: Jeff M Lowery.

” У меня есть хитрый план … »

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

Основная идея была это:

input AddBookInput {
            ISBN: String!
            title: String!
        }
        
input RemoveBookInput {
            bookId: Int!
        }
        
input UpdateBookInput {
          ISBN: String!
          title: String!
      }
      
type AuthorOps {
          addBook(input: AddBookInput!): Int
          removeBook(input: RemoveBookInput! ): Boolean
          updateBook(input: UpdateBookInput!): Book
      }
      
type Mutation {
        Author(id: Int!): AuthorOps
      }

И я использовал эту технику несколько раз без плохого эффекта, но мне повезло. Где проблема?

Читатель указывал мне к проблема На сайте GithQL GitHub, где было указано, что порядок исполнения Вложенные мутации не гарантируется. Uh-ох. В приведенном выше случае я определенно хочу Доклад () Мутация произойдет, прежде чем пытаться updatebook () Операция на одной книге. Увы, только так называемые корень мутации гарантированы выполнять в порядке.

Иллюстрация проблемы

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

type Query {
  noop: String!
}

type Mutation {
  message(id: ID!, wait: Int!): String!
}

Resolver Logs, когда появляется сообщение, то ждет данного времени, прежде чем возвращать результат мутации:

const msg = (id, wait) => new Promise(resolve => {
  setTimeout(() => {
    
console.log({id, wait})
    let message = `response to message ${id}, wait is ${wait} seconds`;
    
resolve(message);
  }, wait)
})

const resolvers = {
  Mutation: {
    message: (_, {id, wait}) => msg(id, wait),
  }
}

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

mutation root {
  message1: message(id: 1, wait: 3000)
  message2: message(id: 2, wait: 1000)
  message3: message(id: 3, wait: 500)
  message4: message(id: 4, wait: 100)
}

Ответ:

{
  "data": {
    "message1": "response to message 1, wait is 3000 seconds",
    "message2": "response to message 2, wait is 1000 seconds",
    "message3": "response to message 3, wait is 500 seconds",
    "message4": "response to message 4, wait is 100 seconds"
  }
}

И журнал консоли говорит:

{ id: '1', wait: 3000 }
{ id: '2', wait: 1000 }
{ id: '3', wait: 500 }
{ id: '4', wait: 100 }

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

Муха в мази

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

const typeDefs = `
type Query {
  noop: String!
}

type MessageOps {
  message(id: ID!, wait: Int!): String!
}

type Mutation {
  message(id: ID!, wait: Int!): String!
  Nested: MessageOps
}`

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

mutation nested {
  Nested {
    message1: message(id: 1, wait: 3000)
    message2: message(id: 2, wait: 1000)
    message3: message(id: 3, wait: 500)
    message4: message(id: 4, wait: 100)
  }
}

Довольно похоже на то, что у нас было раньше, и ответ на просьбу мутации выглядит почти так же:

{
  "data": {
    "Nested": {
      "message1": "response to message 1, wait is 3000 seconds",
      "message2": "response to message 2, wait is 1000 seconds",
      "message3": "response to message 3, wait is 500 seconds",
      "message4": "response to message 4, wait is 100 seconds"
    }
  }
}

Единственное отличие – это ответы упакованы в вложенном объекте JSON. К сожалению, консоль раскрывает сказку о горе:

{ id: '4', wait: 100 }
{ id: '3', wait: 500 }
{ id: '2', wait: 1000 }
{ id: '1', wait: 3000 }

Он обнаруживает, что сообщения обрабатываются вне последовательности: самые быстрые обработки сообщений отправляются в первую очередь.

Хорошо. В коде Из моего оригинального поста я на самом деле сделал что-то большее, как следующее:

mutation nested2 {
  Nested {
    message1: message(id: 1, wait: 3000)
  }
  Nested {
    message2: message(id: 2, wait: 1000)
  }
  Nested {
    message3: message(id: 3, wait: 500)
  }
  Nested {
    message4: message(id: 4, wait: 100)
  }
}

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

{
  "data": {
    "Nested": {
      "message1": "response to message 1, wait is 3000 seconds",
      "message2": "response to message 2, wait is 1000 seconds",
      "message3": "response to message 3, wait is 500 seconds",
      "message4": "response to message 4, wait is 100 seconds"
    }
  }
}

Но так же журнал консоли:

{ id: '4', wait: 100 }
{ id: '3', wait: 500 }
{ id: '2', wait: 1000 }
{ id: '1', wait: 3000 }

Так что тут происходит?

«Проблема» – это то, что GraphQL выполняет вложенную мутацию, возвращая объект с дальнейшими методами мутации. К сожалению, когда возвращается этот объект, Graphql находится в следующем запросе мутации, не знает, что в запросе есть дополнительные операции мутации.

GraphQL элегантно прост, но просто поставляется по стоимости. Это возможно, что вложенные мутации могут быть поддержаны, скажем, добавив Мутатор Тип (его следствие будет вход тип ), который GraphQL будет лечить как расширение операции мутации. Поскольку он стоит, просто не хватает информации в просьбе мутации, чтобы знать, что вложенные операции также являются мутаторами.

Организация мутаций GraphQL, часть 2

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

Полное приложение Nodejs, используемое для этого поста, можно найти здесь Отказ

Оригинал: “https://www.freecodecamp.org/news/beware-of-graphql-nested-mutations-9cdb84e062b5/”