Перейти к содержанию

GraphQL Best Practices

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

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

Ниже приведены краткие описания некоторых из наиболее распространенных передовых практик и приёмов для GraphQL, однако каждая статья в этом разделе будет вдаваться в подробности об этих и других темах.

HTTP

GraphQL обычно передается через HTTP с помощью одной конечной точки, выражающей полный набор возможностей сервиса. В отличие от REST API, который предоставляет набор URL-адресов, каждый из которых представляет один ресурс. В то время как GraphQL может использоваться наряду с набором URL-адресов ресурсов, это может сделать его более трудным для использования с инструментами, как GraphiQL.

Читайте подробнее о Serving over HTTP.

JSON (with GZIP)

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

Это рекомендуется, так-как любые производственные GraphQL услуги позволяют делать GZIP сжатие и поощряют своих клиентов, отправив заголовок:

Accept-Encoding: GZIP

Также JSON хорошо знаком разработчикам клиента и API, а еще его легко читать и отлаживать. На самом деле, синтаксис GraphQL частично вдохновлен синтаксисом JSON.

Versioning

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

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

В противоположность этому, GraphQL возвращает только те данные, которые явным образом запросили, поэтому новые возможности могут быть добавлены с помощью новых типов и новых полей для этих типов, без создания разрывов в изменениях. Это привело к общей практике всегда избегать нарушенияй изменений и обслуживающих безверсионных (versionless) API.

Nullability

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

По недобросовестности каждое поле к NULLABLE, по любой из этих причин может привести к полю, возвращенному в null, вместо того, чтобы провалить запрос. Вместо этого GraphQL обеспечивает non-null варианты типов, которые делают гарантию клиентам, что, если требуется, то поле не будет возвращать null. Вместо того, чтобы, в случае возникновения ошибки, предыдущее родительское поле будет "нулевым" вместо этого.

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

Pagination

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

Как правило, поля, которые могли бы возвращать длинные списки принимать аргументы first и after, чтобы для указания конкретного региона списка, где after является уникальным идентификатором каждого из значений в списке.

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

Server-side Batching & Caching

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

Это обычно решается с помощью метода дозирования (Batching), где множественные запросы из backend собираются в течение короткого периода времени, а затем отправляются в одном запросе к основной базе данных или microservice с помощью такого инструмента, как Facebook's DataLoader.

Большинство типов систем, которые распознают значение null, предоставляют как общий тип, так и версию с нулевым значением (nullable version) этого типа, где по умолчанию типы не включают null, если явно не объявлены. Однако в системе типа GraphQL каждое поле по умолчанию имеет значение NULL (пустое значение по умолчанию). Это связано с тем, что есть много вещей, которые могут пойти наперекосяк в сетевом сервисе, поддерживаемом базами данных и другими службами. База данных может упасть, асинхронное действие может выйти из строя, исключение может быть "выкинуто". Помимо просто сбоев системы, авторизация часто может быть гранулированной, когда отдельные поля в запросе могут иметь разные правила авторизации.

По умолчанию каждое поле допускает значение NULL, любая из этих причин может привести к тому, что в этом поле будет возвращено значение null, вместо окончательного провала запроса (сбоя запроса). Вместо этого GraphQL предоставляет ненулевые варианты типов, которые предоставляют гарантию клиентам, которые, по запросу, никогда не возвратят null. Вместо этого при возникновении ошибки предыдущее родительское поле будет «нулевым».

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