В отпуске появилось по-больше свободного времени, чтобы «оглянуться по сторонам» и заняться давно интересовавшими меня технологиями. В этой записи будет краткое резюме по GraphQL.
GraphQL — это стандарт декларирования структуры данных и способов получения данных, предложенный и реализованный Facebook.
Существует несколько реализаций GraphQL:
- От Facebook — http://graphql.org/code/ Тут, правда, странность в том, что базовую технологию https://github.com/graphql/graphql-js не рекомендуют к production. Там же в наборе есть Relay — в чём-то аналог Redux, заточенный на выемку данных с помощью GraphQL-запросов.
- От Apollo — http://www.apollostack.com/ Тут ребята постарались сделать full-stack, причем клиентская часть основана на Redux. Минус их в том, что есть задержка в реализации последних версий стандарта GraphQL: сейчас, например, нет stream, defer и пр., технологий ускоряющих работу с многостраничными данными и часто-обновлямыми элементами. Не думаю, что это прям критичный минус, но это стоит учитывать.
- И еще 3-4 штуки можно найти тут — https://github.com/chentsulin/awesome-graphql.
Там же можно найти библиотеки, реализующие GraphQL, на практически всех современных языках программирования, кучу различных примеров реализаций, способов визуализации запросов и пр. и пр.
Что мне понравилось в этой технологии:
1. Декларативное описание структур данных, которые можно запросить с сервера. Только посмотрите на эту красоту:
type Entity { _id: String title: String category: EntityCategory } type EntityCategory { _id: String title: String } type RootQuery { entity(_id: String): Entity entities(limit: Int): [Entity] } schema { query: RootQuery }
Так мы описали, например, что с сервера можно запросить Entity с полями _id, title, category типа EntityCategory. В apollo-stack эта строка будет автоматически преобразована в стандартный объект GraphQLSchema.
2. Удобное написание функций, получающих данные (resolvers):
module.exports = { RootQuery: { entity(_, { _id }) { // Тут ожидается либо Promise, либо просто значение return vEntities.vertex(_id).then(v => v.vertex); }, entities() { return vEntities.all().then(cursor => cursor.all()); } }, Entity: { // Эта функция будет вызвана, только если у Entity также запросили category. Также можно вернуть Promise, который зарезолвится с нужными данными. category(entity) { return { _id: 1, title: 'Category A' }; } } };
3. Язык запроса данных и Web UI GraphiQL (супер легко подключается к express) с очень крутой валидацией запросов и auto-complete, который учитывает текущую схему. Например, запросим только поле title у Entity по id:
{ entity(id: "1") { title } }
Из минусов можно отметить не очень понятную документацию на graphql.org (а вот у Apollo по тем же вопросам документация отличная) и официальная клиентская библиотека Relay, использование которой означает отказ от Redux.
Итого
Я вижу GraphQL как весьма удобную альтернативу классическому REST API: гораздо удобнее иметь одну «ручку», в которую можно слать разнообразные запросы на получение или изменение данных (тут они называются мутациями (mutation) и декларативное описание структуры данных, чем портянку из обработчиков путей типа req.get(‘/entities’), req.post(‘/entitites’), req.put(‘/entities/:entityId’) и т.д.
Также такой подход облегчает формирование единого state для react-приложений.