Facebook представил новый язык формирования запросов GraphQL

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

Для загрузки доступен черновик спецификации GraphQL, эталонная реализация на языке JavaScript, библиотека с парсером для C/C++, серверные обвязки для различных языков программирования (Go, Ruby, Scala, Java, .Net, Python) и набор сопутствующих инструментов, в том числе работающая в браузере интегрированная среда для формирования запросов graphiql и серверные компоненты для swapi и express. Код открыт под лицензией BSD.

Последние несколько лет GraphQL активно используется в Facebook и служит основой для абстрагирования потоков данных в мобильных приложениях для Android и iOS. GraphQL позволил уйти от практики разработки мобильных приложений в виде надстройки над вариантом сайта Facebook для мобильных устройств в сторону самодостаточных программ с логикой выполнения на стороне клиента. При реализации парадигмы Model-View для получения данных отлично подходит формат JSON, но существующие методы для отправки запросов, такие, как REST и ad hoc, не отвечали требованиям Facebook и требовали выноса части логики на сторону сервера, не обладая должной универсальностью. Facebook попытался решить эту проблему в GraphQL и за последние три года перевёл все свои мобильные приложение на данную технологию.

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

0_1442302729.jpg

Особенности GraphQL:

  • Явное задание формы данных — ответ отзеркаливает поля, указанные в запросе, что позволяет точно знать какие именно данные будут получены и какого они будут типа;
  • Иерархическая организация, позволяющая отследить взаимосвязь между объектами без необходимости отправки повторных запросов и формирования сложных условий слияния (в отличие от RESTful-систем и SQL). Иерархия данных задаётся с использованием структуры в форме графа и отлично сочетается с потребностями, возникающими при построении интерфейсов пользователя;
  • Жесткая типизация — каждый уровень запроса GraphQL связывается с определённым типом и для каждого поля декларируется свой тип (по аналогии с SQL) Такой подход позволяет выявить ошибки на этапе до выполнения запроса и даёт возможность повысить качество клиентских программ;
  • GraphQL является лишь протоколом, не налагающим каких-либо требований к характеру хранилища. На сервере за каждое поле GraphQL отвечает определённая функция, что позволяет легко адаптировать взаимодействие с клиентами по GraphQL в имеющиеся кодовые базы, без изменения существующих схем хранения и бизнес-логики;
  • Возможность получения сведений о поддерживаемых сервером данных. У сервера GraphQL можно запросить список поддерживаемых типов и получить более полные сведения о возможностях предоставляемого сервером API, без необходимости изучения кода и спецификаций; 0_1442304015.jpg
  • Независимость от версии серверного API — так как форма возвращаемых данных задаётся клиентом, серверное API может расширяться без опасности нарушения совместимости с клиентским ПО. Например, на сервере могут быть реализованы обработчики новых полей, которые будут применяться только для версий клиентов, поддерживающих эти поля, а для старых клиентов будут игнорироваться.

Пример типов:

     enum Episode { NEWHOPE, EMPIRE, JEDI }       interface Character {       id: String       name: String       friends: [Character]       appearsIn: [Episode]     }       type Human : Character {       id: String       name: String       friends: [Character]       appearsIn: [Episode]       homePlanet: String     }  

Пример запросов:

     query HeroNameQuery {       hero {         name       }     }       query HeroNameAndFriendsQuery {       hero {         id         name         friends {           id           name         }       }     }    

©  OpenNet