Теперь в спецификации есть открытый RFC для подписок!

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

Существующие типы операций GraphQL

GraphQL - отличный язык запросов API для извлечения данных. Если вы не слышали об этом или о преимуществах, которые вы можете получить, узнайте об этом на graphql.org.

В текущей версии спецификации GraphQL поддерживает два типа операций:

  1. Запросы - используются для получения данных.
  2. Мутации - используются для записи данных.

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

Введите подписки GraphQL

Практически после того, как GraphQL был выпущен Facebook в качестве технологии с открытым исходным кодом в 2015 году, люди активно обсуждали новый тип операции под названием Подписки GraphQL, который добавляет концепцию передачи данных на стороне сервера.

Первоначально эта идея была вызвана докладом и записью в блоге от Лэйни Кюнзела и Дэна Шафера из Facebook об их внутренней реализации новой технологии. За этим последовал год производственного тестирования в Facebook и экспериментов в сообществе, в основном вокруг ориентированного на сообщество предложения и набора реализаций, предложенных командой Apollo.

Вчера был сделан первый конкретный шаг к добавлению подписок в спецификацию: это запрос на вытягивание в репозитории спецификаций GraphQL от инженера Facebook Роберта Чжу.

Что такое подписка GraphQL?

Прежде чем мы перейдем к деталям предложения, о чем мы здесь вообще говорим? Что ж, во всех обсуждениях подписок на конференциях Facebook и экспериментах в сообществе, вот консенсус высокого уровня:

Подписка - это запрос GraphQL, который просит сервер отправить несколько результатов клиенту в ответ на какой-либо триггер на стороне сервера.

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

Пример: добавлен комментарий

Например, у вас может быть поле подписки с именем commentAdded(postId: ID!), которое представляет поток новых комментариев, добавленных к определенному сообщению. Затем вы можете запросить его с помощью следующей операции подписки GraphQL:

subscription {
  commentAdded(postId: "ac55aa55") {
    comment {
      id
      content
      author { username }
    }
  } 
}

Это может дать несколько результатов в течение срока действия подписки:

// Result 1
{
  "data": {
    "commentAdded": {
      "comment": {
        "id": "abc123",
        "content": "GraphQL subscriptions will be awesome!",
        "author": { "username": "sashko" }        
      }
    }
  }
}

// Result 2
{
  "data": {
    "commentAdded": {
      "comment": {
        "id": "def456",
        "content": "We should have a good RFC discussion!",
        "author": { "username": "robzhu" }        
      }
    }
  }
}

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

Другой пример: Webhook

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

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

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

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

Что такое подписка * не *?

Как упоминалось в документе RFC, подписка - это не оперативный запрос. Что это обозначает? Самая большая разница - это контракт, который он представляет с сервером. Если бы в GraphQL была официальная функция, называемая «живым запросом», можно было бы ожидать, что она всегда будет предоставлять вам обновления о запрошенных данных. Например, вы можете запустить оперативный запрос к определенному сообщению и списку комментариев к нему и рассчитывать на получение эффективных обновлений, когда что-либо изменится - содержимое публикации, содержимое комментариев, новые комментарии, удаленные комментарии и т. Д. Это заметно отличается, потому что подписки повторно запускаются только в очень определенных случаях и не гарантируют уведомления вас обо всех видах изменений данных.

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

Что в спецификации?

Цель спецификации GraphQL - быть как можно более ясной, но при этом минимальной - она ​​не включает ничего, кроме самого необходимого. Например, спецификация запросов и мутаций относится к концепции запроса и ответа, но не говорит конкретно о HTTP, прокси, CDN, балансировке нагрузки или любых других деталях, о которых вам действительно нужно подумать, чтобы запустить Сервер GraphQL в производстве.

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

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

Следующие шаги для RFC

Процесс положил начало отличному началу: инженеры Facebook, работающие над этим RFC, были открыты для отзывов и обсуждений с разработчиками популярных библиотек GraphQL. Кроме того, обнадеживает то, что текущее предложение учитывает как внутренние потребности Facebook, так и существующую работу сообщества. Куда может пойти RFC?

Обсуждение и различные варианты использования

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

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

  1. Организации, использующие GraphQL в производстве
  2. Авторы серверов и клиентов с открытым исходным кодом
  3. Организации, которые могут принять GraphQL, если он получит функцию подписки

Пришло время вмешаться, и ваш голос будет услышан, прокомментировав пул-реквест.

Подсветка открытых вопросов

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

  1. Отказ от подписки. Выполняется ли отмена подписки с помощью специфической для GraphQL функции, такой как синтаксис языка, или она зависит от транспорта, поэтому она должна быть вне GraphQL?
  2. Несколько подписок в одном запросе. Что происходит, когда у вас есть несколько корневых полей или несколько операций подписки в одном запросе? Казалось бы, это подразумевает подписку на разные виды событий, поэтому пока не ясно, что должно произойти. Если это разрешено, будут ли они запускаться повторно одновременно или по отдельности? В качестве альтернативы, возможно, в запросе подписки должно быть разрешено только одно корневое поле или операция подписки.
  3. Ошибки. Как отправляются сообщения об ошибках? Набор возможных ошибок в системе увеличивается, когда вводится механизм с отслеживанием состояния. Что происходит, когда сервер решает прекратить отправку новых результатов подписки, или текущий пользователь выходит из системы, или при выполнении одной конкретной подписки возникает ошибка времени выполнения? Я подозреваю, что это не будет очень спорным, но это одна из тех вещей, которые должны быть решены, чтобы спецификация была полезной.
  4. Требования к транспортировке. Какие транспортные функции необходимы для этого? Можете ли вы оформить подписку, состоящую из одного запроса и одного ответа, или же критически важно иметь возможность отправлять несколько ответов? Требуется ли для транспорта явная концепция «подключения» или поддерживаемый набор транспортов включает в себя что-то вроде push-уведомления, когда вы не можете определить, находится ли получатель в данный момент в сети?

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

Эксперименты и реализация

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

Прибываем к финальному обновлению спецификаций

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

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

Нам не терпится увидеть, что дальше будет дальше с этим предложением. Это первый крупный RFC для спецификации GraphQL, в котором также представлен новый процесс добавления функций, над которым работала основная группа GraphQL. Давайте вместе соберемся и сделаем все как можно успешнее!

Подписки в вашем приложении GraphQL.js

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

Реализовать собственную совместимую систему подписок с нуля не очень сложно, но если вы хотите быстро приступить к работе, мы создали несколько пакетов, которые вы можете легко использовать, если используете сервер и клиент JavaScript. Пожалуйста, попробуйте их и поделитесь на GitHub!

Graphql-подписки

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

Подписки-транспорт-ws

Это транспортная библиотека websocket, которая реализует простой клиент и сервер, который управляет жизненным циклом подписки, отмены подписки, аутентификации и обработки ошибок по сети. Вам не нужны дополнительные библиотеки, такие как Socket.io или аналогичные, поскольку этот пакет обрабатывает все, что вам нужно для подписок GraphQL. Предполагается, что вы будете отправлять запросы и изменения через «стандартный» HTTP-транспорт и только подписки через веб-сокет.

Чтобы увидеть оба этих пакета в действии вместе, посмотрите этот простой файл в нашем примере приложения GitHunt. У нас также есть живой пример! Откройте этот канал комментариев на нескольких вкладках и отправьте комментарий, затем посмотрите, как он появится на другом экране.

Также ознакомьтесь с нашей документацией о подписках:

  1. Subscriptions React docs: как обрабатывать подписки в вашем приложении React
  2. Подписки GraphQL Server docs: Как добавить подписки GraphQL на ваш сервер Node

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

Чтобы узнать больше о подписках GraphQL от команды Apollo, прочтите наши предыдущие сообщения в блоге:

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