Pull to refresh

Comments 282

Т.е. вместо того чтобы отталкиваться от предметной области задачи, требований к данным со стороны клиента.
люди постоянно придумывают себе границы в виде каких-то REST API или GraphQL, которые вместо того чтобы помогать, на самом деле только ограничивают гибкость.
Что мешает думать о HTTP API как об интерфейсе команда-результат, где не обязательно наличие каких-то осмысленных ресурсов, CRUD и т.п. операций.
Зачем это всё?
как об интерфейсе команда-результат

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


PS вообще подобный OData стандарт существовал до GraphQL.

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

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

По аналогии с SQL, если вы откроете доступ к БД, то злоумышленник может сделать SQL запрос с кучей join которые тупо повесят ваш сервер БД (вам же это не хочется, правда ?). Разве сам по себе GraphQL может защитить от такой участи? Я думаю нет, а раз нет — то зачем это всё нужно?

а БД как решает проблему кучи джойнов? И почему GraphQL ее должен решать, если это не его задача?

А вы выставляете БД в мир и говорите, приди сюда плохой человек, я дам своему хостеру 100500 денег на твой запрос?

GraphQL — решение для публичного API, поэтому он должен решать этот вопрос. Иначе грош цена дырявому интерфейсу.
А вы выставляете БД в мир и говорите, приди сюда плохой человек, я дам своему хостеру 100500 денег на твой запрос?

нет, конечно. Я, как разработчик api, и в graphql не дам выполнять все что душе угодно.


GraphQL — решение для публичного API, поэтому он должен решать этот вопрос. Иначе грош цена дырявому интерфейсу.

graphql — это спецификация клиентского апи, и не описывает серверную реализацию от слова "совсем". Так же как спецификация языка sql не описывает реализацию базы данных и защиту от множественных джойнов.

Ваш сервер либо соотвествует спецификации и тогда это GraphQL сервер, либо нет.
> нет, конечно. Я, как разработчик api, и в graphql не дам выполнять все что душе угодно.
ну т.е. мы пошли в софизмы и теперь говорим что где-то мы поддерживаем GraphQL, а где-то нет.
Значит вы делаете не GraphQL сервер.

Мой вопрос состоит в том, как из самого запроса понять его сложность? Понять насколько он сложен для машины, и вовремя его отбросить чтобы заняться чем-то другим. Есть решения этого вопроса?
Когда вы делаете SQL-запрос, сервер обязан отдать вам результат и он его ищет.
Когда вы делаете GraphQL запрос, вы вольны делать что угодно. Но опять же в случае какого либо RPC (как выше назвали этот подход), это позволяет контроллировать все аспекты взаимодействия. И т.о. даже если клиент генерирует вредоносные для сервера запросы, сервер может их просто игнорировать используя простые правила фильтрации.
В случае GraphQL, эта спецификация дает бесконечное множество путей получения данных.
И мой вопрос состоит в том, каким образом это множество можно ограничить до разумных пределов, чтобы контроллировать производительность сервера и «хорошие намерения» клиента.
Вопрос понятен?
И мой вопрос состоит в том, каким образом это множество можно ограничить до разумных пределов, чтобы контроллировать производительность сервера и «хорошие намерения» клиента.

даже если клиент генерирует вредоносные для сервера запросы, он может их просто игнорировать используя простые правила фильтрации

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

Спецификация — это спецификация. Таким же макаром можно поддреживать ограниченный SQL и все тоже самое будет. Меня интересует вопрос более общего плана.
В случае RPC мы каждой команде можем сопоставить однозначную стоимость её выполения, причем сделать это заранее.
Когда за единицу времени клиент генерирует слишком большую стоимость, мы можем его игнорировать.
Теперь возьмем «универсальный интерфейс», которые позволяет нам генерить кучу запросов, и получать данные даже такие, которые разработчик интерфейса и не думал что они будут запрошены.
Мой вопрос состоит в том, как из самого запроса получить стоимость его выполнения?
В случае RPC всё просто, в случае GraphQL всё неоднозначно. Пока не выполнилнишь, не поймешь. Т.о. этот универсальный путь открывает такие очень хорошие возможности по «нагружанию» вашего сервера. А зачем оно вам вообще это надо?
В случае RPC всё просто, в случае GraphQL всё неоднозначно.

на самом деле ни в первом ни во втором случае не все так, как вы говорите. Необязательно стоимость запроса известна заранее, если RPC поддерживает вложенность ответа (а RPC это не оговаривает), и необязательно стоимость заранее неизвестна при работе с GraphQL, если сервер позволяет запрашивать сущности 1-2 вложенностей максимум, без рекурсии (реализацию GraphQL тоже не оговаривает).
Это все детали реализаций — вложенность, рекурсия, rate limiting, security, authorization/authentification итд. Сама спека только о языке запросов.

Накрутив на GraphQL-сервер контроль вложенности, рекурсии, rate limiting, security, authorization/authentification и т.д. получится REST-API с чётким разделением ресурсов. GraphQL — это просто «ленивое» проектирование (REST-подход «заставляет» планировать иерархию ресурсов и ограничений чуть раньше, чем GraphQL), вступающее в конфликт с идеологией веба и всего промежуточного ПО (помимо контроля доступа к данным и нагрузки на сервер GraphQL кладёт большой болт на кеширование). Больше принципиальных отличий между этими двумя подходами в построении API нет.

принципиальное отличие — это эндпойнты снаружи у rest и ресолверы внутри у graphql. Кладет или не кладет болт graphql на все точно так же, как и rest.
Весь "обвес" — это атрибуты любого апи, и они не сделают из graphql rest или наоборот. Они банально работают на другом уровне.

Да, GraphQL прячет резолверы ресурсов внутрь, делая бесполезными коды ошибок HTTP, глаголы HTTP, заголовки HTTP, используемые промежуточным ПО для кеширования и контроля работы с данными. Именно об этом я и говорю, GraphQL — это «ленивое» проектирование, которое удешевляет разработку на старте проекта, но удорожает на дальнейшей разработке и поддержке.

по-моему наличие промежуточного ПО из коробки удешевляет старт, потому что не нужно продумывать например кэширование непосредственно в приложении. По мне так разница небольшая: нджинкс у меня будет кэшировать, или мидлваря перед graphql.

Удешевляет старт возможность начать с низкоквалифицированными программистами, не вникая в сложности HTTP/REST. А мидлвари не все принадлежат вашей инфраструктуре. Ну и потом да, нанимать квалифицированных программистов, которые из ваших мидлварей сделают всё то, что уже спроектировано в HTTP.
Удешевляет старт возможность начать с низкоквалифицированными программистами,

Это миф. Бездумная копипаста слишком быстро начинает затягивать проект в болото.


не вникая в сложности HTTP/REST.

Да какие там сложности?

> Это миф. Бездумная копипаста слишком быстро начинает затягивать проект в болото.

Это не миф, а лишь моё мнение, попытка найти причину существования GraphQL. Сам я тоже предпочитаю чуть больше проектировать, чем плавать в болоте копипаст.

> Да какие там сложности?

Да, сам тоже, конечно, не считаю сложным то, в чём уже имею компетенцию :).
Удешевляет старт возможность начать с низкоквалифицированными программистами, не вникая в сложности HTTP/REST. А мидлвари не все принадлежат вашей инфраструктуре. Ну и потом да, нанимать квалифицированных программистов, которые из ваших мидлварей сделают всё то, что уже спроектировано в HTTP.

Дешевые низклквалифицированные специалисты – это очень дорого.

А найм высококвалифицированных, которые потом перепишут все заново – это еще дороже.

Такое себе удешевление получается =)
Современные стартапы часто работают так: «на карманные деньги» и максимально быстро пишется MVP, минимальный прототип, который хоть как-то шевелится, демонстрируется рабочесть идеи, убеждаются инвесторы, даются денег на разработку, и только тогда нанимается полноценная команда и проект делается с нуля. Удешевление возникает не на одном проекте, а на (условно) сотне, из которых 99 всё равно будут отвергнуты, и только один «выстрелит». См. «посевное финансирование».
Вы уверены, что знаете как работает GraphQL?
По аналогии с SQL, если вы откроете доступ к БД, то злоумышленник может сделать SQL запрос с кучей join которые тупо повесят ваш сервер БД (вам же это не хочется, правда ?).


именно поэтому удобно использовать хранимые процедуры, к которым доступ открыт, а к таблицам и прямыми запросами к ним закрыт. в процедуре об этом злоумышленнике подумали заранее.
Если GraphQL API не публичный и предназначен для внутренних клиентов (мобильных или веб), можно использовать списки доступа и предварительно одобренные запросы. Клиенты требуют сервер выполнить такие запросы, указывая вместо запроса его идентификатор. Кажется, Facebook применяет такой подход.
Всё что выставлено наружу — всё публичное. Любой протокол который ходит через публичные сети может быть просниферен, клиент может быть взломан и протокол взаимодействия узнан третьей стороной.
Соотвественно эта третья сторона может использовать ваш GraphQL чтобы нагружать сервера, чего никому не хочется.
указывая вместо запроса его идентификатор

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

Точно так-же как можно нагружать REST или RPC
Необязательно публичным. Пусть злоумышленник сначала авторизуется и станет доброумышленником.
Сама идея GraphQL довольно странная и действительно непонятно, зачем вся эта гибкость без контроля.
Я всегда делаю нечто среднее — при необходимости join'a добавляю к ресурсу эндпоинт с суффиксом типа «with_extra_data» (условно) и возвращаю приджоиненные данные. И клиента ограничивает, и 10 запросов не нужно гонять.
+1, GraphQL кажется полезным, возможно, для работы только с действительно графовыми данными (например, для извлечения френдов выбранной «дальности» из социальной сети). В иных случаях таки кажется полезнее разобраться с «математикой» REST и всеми наработками, уже реализованными в HTTP для него.
Сама идея GraphQL довольно странная и действительно непонятно, зачем вся эта гибкость без контроля

да почему без контроля-то? контролируйте.

UFO just landed and posted this here
И всё будет обрастать классами, функциями, ифами для валидации запросов? Интересно даже, как подобный контроль возможен, если GraphQL — библиотека, и наверняка всё очень инкапсулированно.
Конкретные эндпоинты для конкретных функций интерфейса будут намного чище и поддерживаемее.
Грубо, одна кнопка на сайте — один эндпоинт. Нет прав для запроса конкретных данных — бросил ошибку.
GraphQL сразу предлагает дропнуть целый уровень абстракции вместе с системой ролей и не предлагает ничего взамен.

GraphQL — не библиотека, а спецификация. Есть референсная реализация на JavaScript и есть много альтернатив на разных языках, как клиентов, так и серверов.

https://stackoverflow.com/questions/37337466/how-do-you-prevent-nested-attack-on-graphql-apollo-server

Query whitelisting: This is probably the most involved method, but you could compile a list of allowed queries ahead of time, and check any incoming queries against that list. If your queries are totally static (you don't do any dynamic query generation on the client with something like Relay) this is the most reliable approach. You could use an automated tool to pull query strings out of your apps when they are deployed, so that in development you write whatever queries you want but in production only the ones you want are let through. Another benefit of this approach is that you can skip query validation entirely, since you know that all possible queries are valid already.

предварительно одобренные запросы
UFO just landed and posted this here
В проде, да, не нужна, в девелопменте почему нет?

В большинстве случаев такая гибкость не нужна в продакшене, достаточно гибкости при разработке/отладке/тестировании. Все эти хот релоад, дев-окружения и т. п. так и работают — не в прод окружении всё гибко, а на прод статически собирается и фиксируется.

То, о чем вы пишете есть RPC и существует очень давно. Разве что раньше никак не называли этот подход, а начали называть только с приходом REST и иже с ними.

Когда вы занимаетесь разработкой как backend, так и frontend, то можете «точить» одно под другое. Но, если у вы пишете только backend, а frontend будут писать совсем другие люди и коммуникации между вами не будет, то вы не можете заранее знать что frontend будет «хотеть».

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

Пример: Публичное API.

Согласитесь, что Facebook, например, скорее всего не будет затачивать свое API для вашего мобильного приложения. Т.е. взаимодействия между разработчиками API и разработчиками frontend'а нет и в данном случае быть не может.
Не соглашусь. Разработчики API facebook понимают какие данные нужны людям, и предоставляют эти данные в удобном для людей виде. Т.о. взаимодействие есть, но косвенное.
Не бывает сферического API в вакуме. В случае GraphQL это именно этот конь и есть.
Они не могут знать что надо всем. Потому что кому-то что-то надо, а кому-то нет. Кто-то может сделать дополнительный запрос, а кому-то это «дорого».

Когда вы сами пишете API, вы можете все «запихать» в 1 запрос. Когда вы используете чужое API, возможно 2 и более запросов. Хуже, когда все выливается в N+1 запросов. А все потому что разработчик API не может знать что вам надо и делать API для вас. У него таких как вы еще 100500 и каждому что-то надо. И в случае с REST такое бывает часто.

И да, не бывает сферического API в вакуме. О чем я и пишу.
Я с вами согласен по части «не могут знать», поэтому они делают как лучше для них.
Конечно, вы можете сделать 2 запроса и получить 2 результата на что уйдет 2х времени.
Если вы хозяин API, и видите боль, ну ничего не мешает вам организовать простой интерфейс где возможно сразу выполнить много команд. Проблемы возникнут когда одна команда зависит от другой. Конечно, GraphQL, возможно, решает эту проблему, но опять же я вижу другую проблему — это слишком общий путь получания данных, и эта очень сильная беда как с точки зрения реализации, так и с точки зрения ограничения нагрузки.

Я как бы не против всяких GraphQL и SQL. Я против того, чтобы это было выложено в паблик без должной работы по ограничению стоимости запросов. И т.о. сам запрос должен содержать в себе информацию о том, какова его сложность выполнения. Есть работы по анализу этого?
У них когда-то был FQL. Но его закрыли.
Вот как сейчас у Facebook спросить список галерей с количеством фотографий в них? У самой галереи нет счатчика? Запросить сразу все фотографии нельзя. Там еще пейжинг есть.

С их текущим REST это сделать очень больно.
Как с помощью GraphQL это сделать? Т.е. не просто ограничить набор полей в выводе, а добавить агрегирующие функции?

С помощью FQL это было сделать можно. Но, нет больше FQL.
Зачем это всё?

Ваш вопрос из той же оперы что и например — зачем нам Симфони когда можно отлично закодить на PHP/HTML mixed, не находите?)
Нет. Я понимаю ваше стремление улучшить API? которое предоставляется. Но, вы не понимаете моё стремление обезопасить протокол. Когда вы используете принцип простая команда-результат, вы видите всё что происходит на вашей стороне, вы можете собирать статистику о том какая команда сколько стоит. Соответственно, вы можете решать заранее, можно выполнять команду или нет для клиента.
В случае GraphQL вы не знаете какие конкретно запросы будет слать клиент, это множество значительно больше того множества запросов когда вы используете RPC, соотвественно вы не можете предсказать сложность запроса и время его выполнения, т.к. это множество ОЧЕНЬ большое.

Вы сделали интерфейс взаимодействия аля SQL и выставили его наружу.
Поддерживаю вас.
Почему-то многие разработчики стреляют себе в ногу, когда пытаются использовать технологии не осмысленно, а хайпово.
К примеру REST — хорош для CRUD приложений. Как только выходишь за рамки манипуляции объектами, то приходится создавать странные маршруты вроде GET /postsAndComments/.
GraphQL — ради одной точки входа создаём себе кучу проблем вроде непредсказуемого API c потенциальными дырами в безопасности.

Можете меня не поддерживать, но на текущий момент вижу удобным сочетание REST (для CRUD действий над объектами) и JSON RPC (для всего остального) с добавлением OData по необходимости.
GraphQL — ради одной точки входа создаём себе кучу проблем вроде непредсказуемого API c потенциальными дырами в безопасности

Никто не мешает в GraphQL реализовать ресурсы в точность так же для CRUD. Откуда берется непредсказуемость и дыры — не ясно, посмотрите примеры, github, например.
Можете даже root-объекты назвать по привычке GET DELETE PUT POST
query{
GET {
post(id:1){
title
}
}
}
Мне кажется вы подменяете понятия защищая GraphQL любыми средствами.

Я не настолько люблю REST, чтобы создавать рут-объекты с именами GET, POST и т.д. Я сторонник принципов KISS и DRY, которые не про GraphQL. Конечно DRY и не совсем про REST тоже…

Было бы намного практичнее, если бы вы привели пример API, реализованного на GraphQL и документации к нему. А ещё лучше сравнение с аналогичным API на REST.

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

Я привел пример https://developer.github.com/v4/, ну и https://developer.github.com/v3/
Гитхаб шли по абсолютно тому же пути, придумывали способы описать запрашиваемые поля, а когда вышла спека GraphQL просто заюзали его.
По поводу дыр в безопасности — насколько я понимаю на GraphQL довольно сложно реализовать систему ролей пользователей, т.к. существует почти бесконечное множество возможных запросов.

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

posts { comments { posts } } }

Где, posts Array Of Post, а на Post свои права доступа, а на вложенный Post те же самые права доступа и та же самая документация.

Но опять же, GraphQL абсолютно не заставляет вас быть настолько гибкими, пожалуйста. реализуйте свои явные точки входа, тогда в виде бонуса будет удобный синтаксис и уменьшенный размер пакета из-за выбора полей.
KISS и DRY, которые не про GraphQL
В моём понимании, GraphQL — это вполне себе KISS (по крайней мере, он гораздо более KISSный, чем классический REST-style подход).
Не могу сказать, что запросы с непредсказуемым количеством комбинаций KISSней, чем REST с его набором стандартных методов. Да, а JSON RPC — ещё более KISSный…

ЗЫ: Под принципом KISS я понимаю создание максимально простого, прямолинейного и легко поддерживаемого и модифицируемого кода. Т.е. иногда лучше написать 1000 строк такого кода, чем 50 строк с мудрённой логикой в которой тяжело разобраться. Да и не забывайте, что библиотека GraphQL — это тоже сложный кусок кода, поддверженный уязвимостям и ошибкам, в то время как REST — простой и прямолинейный протокол взаимодействия.
А в каких случаях используете OData? Где-то в мелькало упоминание Falcor не приходилось использовать?
когда команда — некий идентификатор команды + список некоторых параметров для этой команды.

Так делаем сколько нужно ендпоинтов с соответствующей логикой и все, это REST API и есть. Называет ендпоинты командами или чем угодно, а не сущностями и все. Так делают уже десятки лет.


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

Только это уже будет не REST, а RPC. Хороший (и удобный) REST API написать достаточно тяжело. Очень легко скатиться и начать нарушать его принципы. Иногда оправдываясь такими словами как первоманс.

Если смотреть на детали, то да, но REST просто получается более частная форма вызова конкретных ендпоинтов.

Все верно.
RPC — делаю что хочу и как хочу. Уже REST есть какие-то правила.
А вот воблюдать их или нет — дело выбора каждого.
По большому счету и даже не по большому, REST это тоже RPC)
GraphQL просто позволяет более развернуто задать параметры этого вызова.
RPC — это когда действие определяется урлом или параметрами запроса, а REST — когда исключительно глаголами HTTP. Хоть эти подходы и выразимы друг через друга, но являются принципиально различными подходами к проектированию.
а REST — когда исключительно глаголами HTTP

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

Если хочется абстрагировать REST от HTTP, то пусть будет не «исключительно глаголами HTTP», а «исключительно глаголами из фиксированного списка».

Нет в признаках REST-архитектуры требования фиксированного списка глаголов. Более того, она подразумевает, что список возможных действий над ресурсом становится доступным клиенту только после получения представления ресурса, клиент может даже не знать ничего о действии кроме того, что показать пользователю его название, а потом выполнить запрос, описанный в представлении ресурса.

Вы явно перепутали REST с чем-то другим. HATEOAS говорит о связанных ресурсах, а не действиях над ними, действия для всех ресурсов строго одинаковые (не всегда доступные в полном количестве — об этом коды ошибок HTTP). В этой ограниченности глаголов и заключается суть REST.

Это вы явно перепутали REST c HTTP. Откройте хоть вики что ли и посмотрите пример HATEOAS — там явно описаны действия (ваши глаголы), которые можно совершить над ресурсом и никакого отношения к глаголам HTTP они не имеют. Вернее могут иметь, где-то на уровне документации описано, например, что действие


<link rel="close" href="https://bank.example.com/accounts/12345/close" />

должно осуществляться исключительно методом POST, а может HEAD, а может любым методом.


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

Вы написали «можно не следовать ресурсной семантике REST, значит, REST позволяет описывать действия, а не только ресурсы». «Можно есть вилкой, а не только ложкой, значит ложки — это вилки». Link rel[ation] описывает ссылку на отношение с другим ресурсом и никак иначе, и действие прикладной области придётся выражать в виде ресурса «операция», а не глагола действия над ресурсом.

Я написал "можно не следовать ресурсной семантике HTTP, но при этом не нарушать принципов REST при использовании HTTP в качестве траспортного протокола".


Суть в чём — HTTP по сути протокол прикладного уровня, оперирующий идентификаторами ресурсов в виду URI и фиксированным списком операций над ним в виде методов-глаголов c довольно точной семантикой. В целом точную реализацию спецификации HTTP можно считать REST, если следовать ограничениямия типа запрета на сессии. Но сейчас очень популярно использование HTTP в качестве траспортного протокола, нарушая принципы REST и семантику HTTP на уровне HTTP. Но никто не мешает реализовать принципы REST на прикладном уровне, после разворачивания запроса из HTTP-конверта.

Вы написали «можно не следовать ресурсной семантике HTTP, но при этом не нарушать принципов REST», а я ответил «нельзя». Если вы говорите о том, чтобы реализовать «ресурсную парадигму» не используя в такой парадигме HTTP — то кто ж спорит, конечно, можно и поверх сигнальных костров REST построить. О том и говорю, что GraphQL — это наворачивание ещё одного уровня протокола для того, чтобы можно было воспользоваться готовым фреймворком и докрутить ограничения позже, когда нагрузки действительно возрастут или хакеры заинтересуются вашим сервисом. «Ленивый REST».

Принципы REST можно оставить на прикладном уровне, а на траспортном на них наплевать. GraphQL, SOAP и т. п. — это отказ от использования семантики и прочих прикладных возможностей HTTP (довольно ограниченных и/или неудобных во многих случаях), оставляя его транспортные возможности. Реализовывать на прикладном уровне REST или нет — отдельный вопрос.

Можно и от эзернета отказаться, используя сигнальные костры, я полностью с вами согласен.

Сарказм не уместен. У HTTP по спецификации две отвественности — транспорт и семантика, что даже в его названии отражено. Причём семантика слаборасширяемая и ориентированная на CRUD-операции. Решение выделить семантику на отдельный технический уровень уж точно не аналогично решению заменить езернет на сигнальные костры.

Это лишь утрирования для донесения моего мнения. Не понимаю, что ещё вы пытаетесь добиться в этом диалоге.

Донести что HTTP и REST — лишь пересекающиеся области с одной стороны, а с другой, что за не-REST HTTP API может скрываться REST API прикладного уровня, использующей HTTP в качестве траспорта, но почти полностью игнорируя его семантику, например ораничиваясь только GET запросами.

Мне кажется всё сказанное вами очевидным. И кажется, что вы не понимаете акцентов своих собеседников, «проповедуя обращённым».
RPC — это когда remote procedure call. А какая procedure должна быть call, может определяться как глаголами запроса, так и URL. Я имел ввиду в своем посте именно этот аспект.
Глаголами HTTP реализовывать RPC не получится — их ограниченное фиксированное количество. Я имел ввиду в своем посте именно этот аспект.
Да это понятно, на хабре вообще любимое дело, когда каждый беседует с оппонентом «о своем» :)
у GraphQL есть небольшие отличия, которые существенно меняют процесс построения и использования API разработчиками

не скажу ничего нового, но это небольшое отличие заключается в создании ада на зем бэк-енде.

и ведь что характерно, очень много новых постов о GQL почему-то вместо акцента на реальных преимуществах и границах применимости, просто позиционируют его как убийцу REST/SOAP/RPC/чегоугодно… аргументируя это «смотрите как можно через один эндпоинт всё сделать!». мыслевирус в чистом виде.

а то, что статья вроде как бы просто сравнивает подходы, мало меняет её основной посыл.
Статья, на мой взгляд, лишь пытается выделить сущности, выполняющие схожие функции, в двух парадигмах построения API — несмотря на разницу в терминах, деталях внутренней реализации и алгоритмах работы.
Разница в том, что rest описывает правила работы над данными.
А GraphQL описывает ещё и логику, точно также, как и любая другая концепция datastorage.

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

Может кто-то более понятно объяснить суть технологии? Пока вижу кучу шума и небольшую надстройку на старой рабочей лошадкой.
UFO just landed and posted this here
А чем именно это отличается от доступа через апи к нормальной БД со всеми необходимыми ключами, связями и т.д.? Вот прямо сейчас работаю над проектом, где легко можно пойти по такому примерно адресу:

http://192.168.1.175:1337/api/accounts/33/companies

Получим в виде JSON все компании из таблицы companies связанные по внешнему ключу c записью в таблице accounts с id 33.

Причём все эти вещи не прописываются руками, апи умеет читать связи в базе данных и единственное что требуется при обновлении её структуры — запустить скрипт конфигурации.
UFO just landed and posted this here
А нормальная БД — это какая?
Это и есть по сути такой доступ. С возможность делать Select не *, а указывать список полей, джойнить таблицы.
UFO just landed and posted this here
А в ответ ему прилетает

{"error": "Three levels are allowed maximum."}

UFO just landed and posted this here
Ну а точно прилетает?

у вас разве не гипотетический вопрос? как я могу точно ответить? это деталь реализации, к graphql не имеющая отношения.

UFO just landed and posted this here
По моему ответ будет зависить от реализации, а не от того используется GraphQL, REST или что то еще. Если у вас на выдачу коллекции нет лимита, то на больших таблицах результат будет такой же для обычного GET /books.
UFO just landed and posted this here
А что вы будете делать в случае rest и запроса к ресурсу GET /authors x 100500 раз параллельно? Тут запросов в цикле не будет? Теоретическую возможность ограничить кол-во запросов от клиента я даже за решение не приму, это костыль.
точно так же как и в ресте есть параметр limit и его максимум. Если реализовали — лимит есть, если нет — АПИ дырявое, что рест, что графкл
UFO just landed and posted this here
UFO just landed and posted this here

еще раз: реализация ваша. Как хотите так и делайте. На один запрос 5 уровней, на другой 1, на третий — интеллектуально. Это не костыль — это так надо делать.


get-запрос на /products (в парадигме rest) должен отдать миллион продуктов или ограниченное на сервере количество? Решать разработчику серверной стороны.

UFO just landed and posted this here
Сочувствую. Лично я обычно перед внедрением технологии X в проект задаю себе два вопроса:

1) Есть ли в проекте проблемы, которые после внедрения X исчезнут или существенно уменьшатся?

2) Будут ли использоваться те приятные бонусы, которых сейчас нет, но которые появятся после внедрения X?

Если ответом на оба вопроса является «нет», я не внедряю X на проект. Эдакое сочетание «не ломай то, что и так работает» и «не плати за бонусы, которые тебе не нужны».

Хотя иногда, конечно, желание поэкспериментировать с какой-нибудь новой клевой технологией пересиливает здравый смысл.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
И кстати, для приведенного мной варианта трех уровней было бы вполне достаточно, чтобы серверу ощутимо дать под дых.

вы, как разработчик вашего api, знаете сколько уровней достаточно. Столько и сделайте. Сотый раз: graphql не описывает серверную реализацию.


Но как только возникает что-то подобное, сразу становится понятно, что принцесса-то… небритый мужик.

вы просто не понимаете, что эта спецификация о языке запросов

UFO just landed and posted this here

я внимательно читаю:


Еще раз повторяю — Graphql очень крут. Флаг в руки. Но как только возникает что-то подобное, сразу становится понятно, что принцесса-то… небритый мужик.

если принцесса — разработчик, то вы правы. Ведь к GraphQL эти претензии не относятся. Но в комментах к каждой статье про GraphQL одно и то же — а именно непонимание что собственно это такое.


А вот почему от вас бурная реакция — вопрос

если будете внимательнее читать, то не будете переносить свое настроение на оценку моей реакции.

UFO just landed and posted this here
UFO just landed and posted this here
А в случае REST API можно забыть добавить аутентификацию и авторизацию для конечной точки, и злоумышленник получит данные, к которым он по идее не должен иметь доступа.

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

GraphQL — всего лишь концепция построения интерфейса доступа, которая ослабляет связанность клиента и сервера. На мой взгляд, проблема, которую вы описываете, вообще не имеет отношения к тому, на чем у вас реализован API. Это скорее вопросы информационной безопасности.
UFO just landed and posted this here

написано ровно наоборот: если парадигмально по GET /products мы получаем список продуктов, то не надо забывать о здравом смысле (читай, лимите).

UFO just landed and posted this here
у авторов этого чудесного стандарта не нашлось идей, как этот Graphql столь же красиво реализовать, это говорит о многом.

и еще раз: спецификация рассказывает о том как общаются клиент и сервер, а не как сервер обрабатывает запросы.


Вот ниже давали ссылки на json-api. Вы спеку читали? там есть вообще что-то про серверную реализацию? Почему в случае с graphql должна быть другая ситуация?

json-api просто не называют серебряной пулей и убийцей REST :)
Если вы про вложенность, решается элементарно кешированием, все реализации GraphQL это делают в первую очередь, если про объем, то и в REST без лимитов все будет плохо.

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

действительно, было бы интересно, но собственно чего тут обсуждать? все будет то же самое, что и в rest — мидлвари на сервере для авторизации, кэширования, подсчета уровней вложенности, рейт лимитинга. То есть специфика только одна — проверка на рекурсию и многоуровневость запросов.

я, видимо, еще не дорос до проектов с несколькими уровнями вложенности/разделения функционала ))
Я делаю апи в виде тупо методов, в каждом из которых проверяем ключ токена на роль/права, смотрим в редис есть ли кэшированная версия ответа, если нет, делаем селект, сериализуем, отдаем json клиенту. Пытаясь придумать, как это перенести на идеологию GraphQL сразу возникает куча практических вопросов:
1) как УДОБНО понимать к какой таблице и столбцам имеет доступ токен без миллиона if блоков
2) как прикрутить редис к этой истории, если запросы динамические по столбцам. Опять миллион if на проверку есть ли закешированный запрос именно с этим набором?
3) как планировать индексы в БД
4) как делать пост-обработку данных, когда клиент должен видеть не сырое содержимое столбца, а какой-то человеческий вид. Опять миллион if на тему а содержится ли этот столбец в запросе?
Я к тому, что хорошо бы увидеть вообще другой взгляд на решение вышеописанных проблем/сценариев в реальном коде, как это лучше делать, чтобы не изобретать велосипеды в поисках оптимальности.

Я делаю апи в виде тупо методов, в которым проверяем ключ токена на роль/права, смотрим в редис есть ли кэшированная версия ответа, если нет, делаем селект, сериализуем, отдаем json клиенту.

если в rest у вас несколько endpoint'ов, то в graphql у вас несколько resolver'ов. Просто они не снаружи, а внутри, и чуть по другому работают, но суть та же.


на все вопросы ответ один: делайте как делали. graphql к этому никак не относится.

В графе лучших практик — ноль целый ноль десятых

Ну вообще-то зря вы так) Facebook использует GraphQL(like) в своем GraphAPI (Странное совпадение префиксов, да?) и вполне успешно.

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

UFO just landed and posted this here

Навскидку, по сравнению с классическими HTTP-запросами, улучшает:


  • уменьшает объём передаваемых данных в ответе — клиент определяет, что ему нужно с точностью до поля
  • решает проблему множественных запросов типа 1+N — клиент определяет, что ему нужно не в плоской структуре, а в графе объектов. Грубо, указывает, нужно ли ему здесь и сейчас "джойнить" вложенные данные
  • "из коробки" что-то вроде статической типизации, что по утверждениям многих упрощает поддержку
  • увеличивает независимость фронтенд и бэкенд разработчиков. Фронтендеры больше не нуждаются в заказывании "заказывать" бэкендерам новые ендпоинты (или параметризацию имеющихся) для задач типа "тут нам нужно получить только список айдишников постов, тут то же самое, но с названиями и авторами, а тут полностью развернуть дерево комментариев". Бэкендеры один раз описывают то, что у них есть, а фронтендеры комбинируют это как им угодно в своих запросах.
UFO just landed and posted this here
Это самый слабый аргумент в пользу GraphQL. В любом нормальном API по дефолту включен пэйджинг, соответственно врятли за раз передается больше 100 (ну пусть 200) объектов.

Речь, прежде всего, о форме объектов. Грубо, общепринятый REST отдаёт все скалярные поля объектов, да ещё может разворачивать связанные ресурсы и списки без возможности контролировать это с фронтенда.


Опять же — преждевременная оптимизация.

Это не оптимизация, а упрощение клиентской части (пускай и за счёт усложнения серверной). Цепочки запросов сложнее реализовывать, чем один запрос.


С другой стороны, возможно, непродуманный дизайн API.

Ну вот нужно нам на фронтенде показывать то только названия статей, то кроме названий и какие-то связанные объекты, например авторов (авторы — отдельная сущность). По сути у нас три варианта:


  • делаем ендпоинт получения плоского списка статей, в одном из полей которого идентификатор автора, плюс второй ендпоинт получения автора по идентификатору. Классическое 1+N. Ну можно сделать второй ендпоинт по типу batch, по списку идентификаторов
  • делаем один ендпоинт получения списка статей сразу с развернутыми авторами, передавая их даже если сейчас они фронтенду не нужны
  • делаем два ендпоинта — один с плоским списком, другой с развернутым, фронтенд дергает тот который больше подходит.

Как я понимаю это добавит intellisense? Это выглядит довольно полезным, но не киллер фичей.

В том числе, но основное, имхо, проверка корректности запроса до его фактической отправки. В идеале в компайл-тайме.


Команды должны сотрудничать, а не изолироваться.

Речь не про изоляцию, а про уменьшение зависимостей, про увеличение возможностей работать параллельно.


Давайте спустимся с небес на землю. Вы хоть раз видели проект где можно вот так сразу «один раз описать» и потом не переделывать?

Нет, конечно. Но число запросов на переделку (вернее доделку) снижается, когда фронтендеры сами получают возможность формировать запросы на каком-то языке. В рамках имеющейся можели конечно — речь не о создании новіх сущностей, полей, связей, а о показе имеющихся через API. Простой пример: наученный горьким опытом я почти на автомате добавляю в корни агрегатов время создания и модификаци. При согласовании классического API с фронтендерами они об этих таймстампах не вспомнили, или отказались, чтобы уменьшить трафик, соотвественно эти поля остаются только для "служебного пользования". Потом внезапно они им требуются и не хоть пару строк да надо дописать. С GraphQL я бы их сразу включил в тип, сначала бы их не выбирали (благо аналога SELECT * нет), а потом стали бі вібирать, меня не дергая.

P.S,


Всем этим я не пытаюсь сказать, что REST хороший, а GraphQL плохой.

Я тоже не пытаюсь. Как де-факто фуллстэк-разработчик, я в восторге от GraphQL на фронтенде, и испытываю сдержанный оптимизм от него на бэкенде в среднесрочной перспективе. По факту сейчас комбинирую оба подхода: сервисы (в основном на PHP) работают по RESTish, клиент по GraphQL, а а между ними шлюз.

UFO just landed and posted this here
UFO just landed and posted this here
Что-то не могу понять, зачем GraphQL сравнивать с REST; было бы логичнее выбрать похожий по смыслу формат, например json-api

http://jsonapi.org/format/#fetching-sparse-fieldsets (можно указывать, какие поля возвращать)
http://jsonapi.org/format/#fetching-includes (можно указывать связанные ресурсы, и т.д.)
UFO just landed and posted this here
Очень плохо, что GraphQL позиционирует себя как «забейте что там будет думать разработчик на бекенде — сделайте у себя идеальные запросы под любой случай жизни».

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

Не бывает в мире сразу и быстрых, и универсальных, и безопасных решений.
GraphQL себя так не позиционирует, откройте документацию http://graphql.org/:
Ask for what you need, get exactly that

Точность получаемых данных, т.е. выбор только нужных полей, с точностью до одного.
Get many resources in a single request

Представление сложной выборки с помощью одного запроса, с добавлением batch можно получить реально ВСЕ, что нужно одним запросом.
Describe what’s possible with a type system

Строгая типизация запроса, фишка именно в том, что типы включены в спецификацию!

Все сказки про backend — лишь сказки, GraphQL не решает проблем на сервере, но и не создает их, попробуйте и увидите, что ничего не меняется в этом плане. А вот клиент-серверное взаимодействие становится на порядок удобнее. Ну, пока инструменты еще не все готовы, но даже уже с тем, что есть. А уж возможностей понаписать удобств из-за типизации и глубокой интроспекции — сколько угодно, вопрос времени.
Как минимум graphql создаёт на сервере проблему «джойна» заранее неизвестных сочетаний «таблиц».
На самом деле, нет. Фильтрация, группировка и сортировка обычно происходит на верхнем уровне запроса, остальные джойны — по уже выбранным айди. А здесь уже проблем не так много, во-первых, даже дополнительные запросы будут очень легковесны, во-вторых, чаще всего бэкенд, это не просто выборка из реляционной БД и многие вещи лежат в кэше. Это из простых вариантов. А вообще, есть и поинтереснее решение, хотя оно применяются и в любой другой парадигме — это динамический бэкенд, это статистика запросов, на основе которой, определенные джойны выполняются заранее для определенных моделей.
Да и тема слишком узка, для малых проектов, все это не важно, для крупных, там все равно кэширующие решения будут сложнее, чем джойны.

Дальше, никто не мешает, в конце концов, обрабатывать на сервере запрос, как единый и знать, какие джойны понадобятся, текущие популярные реализации в виде иерархических подзапросов — всего лишь один из вариантов. Можно маппить весь запрос на SQL, можно хотя бы вычислять джойны, что угодно.
Потому, что GraphQL не про сервер, а про декларативное представление куска данных, но с описанными типами.

Я не про количество или тяжесть запросов, а про необходимость разработки какого-то механизма маппинга декларативных описаний запросов в императивные команды типа SQL. В случае REST-подобных интерфейсов, такой маппинг простой в общем случае: один ендпоинт — один захардкоженный запрос, возможные "таблицы" известны на этапе проектирования ендпоинта, изменяются только параметры типа идентификаторов. Грубо — один ендпоинт для получения плоского списка постов, второй — для получения его же, но с деревом комментариев.


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

Откуда берется идея, что фронтенд что-то диктует? GraphQL абсолютно не об этом, это всего лишь формат передачи данных, все остальное, и вложенность, и сложность, и известность всех таблиц — решается индивидуально! Не выдумывайте проблемы там, где их нет.
Еще раз, нет никаких проблем в анализе запроса, смотрим, требуется ли клиенту поле «дерево комментариев» и если да, джойним что надо (в вашем случае, запрашиваем второй endpoint, вместо первого). Рассматривайте GraphQL, как возможность не плодя сущности в языке запроса делать то же самое. Т.е. вместо множества endpoint'ов posts и postsWithComments и postsWithAuthors есть
posts и posts { comments } и posts{ authors }.
И маппинг нужен только в случае, если у вас уже есть написанный сервер с готовыми обработчиками запросов для REST. Если пишете сервер для GraphQL с нуля — все эти вопросы уже заложены в архитектуру, вплоть до выбора БД. Уже есть и готовые облачные решения, правда не от крупных вендоров, ждем и их. Parse с поддержкой GraphQL — было бы вообще идеально.
Справедливости ради, в REST для вашего примера тоже можно обойтись одним эндпоинтом с выбором полей или набора полей через query-параметр.
Т.е. изобрести свой GraphQL, без спецификации, готовых решений и т.д. Можно, наверное, все это делали.
Это у HTTP нет спецификаций?! Я придерживаюсь противоположного мнения — это GraphQL приводит к переизобретению REST, позволяя откладывать проектирование ограничений эндпоинтов «на потом». Для тех, кто не осилил REST/HTTP (ресурсная семантика имеет некоторый порог вхождения, примерно как между процедурным и ООП подходами, а спецификация слишком сложна — всё эти коды ошибок, непонятные заголовки, понятия идемпотентности и прочая ересь) и продолжает пилить API в RPC-стиле («Мне нужно просто выполнить действие на сервере! Зачем мне отдельный ресурс?»)
Боже, причем тут HTTP? Как он поможет вам выбрать поля?
GraphQL приводит к переизобретению REST, позволяя откладывать проектирование ограничений эндпоинтов «на потом».

«На потом» — это в вашей голове.
Для тех, кто не осилил REST/HTTP

Боже…
всё эти коды ошибок, непонятные заголовки, понятия идемпотентности и прочая ересь

Ну прям очень сложно, бедные facebook-архитекторы… А идемпотетность вообще только в мечтах и демагогических высказываниях, когда по сути сказать нечего.
«Мне нужно просто выполнить действие на сервере! Зачем мне отдельный ресурс?»

Ну да, давайте спор функциональщина/ООП головного мозга ввернем, чо уж там. И да, не хочу я все называть существительными, назовите это «ниасилил» или порогом вхождения, обычно, это называют здравым смыслом. Это в REST пытаются делать все ресурсами, просто подогнать под удобный, элементарный формат, никакого отношения к реальному миру и языку это не имеет, просто 90% случаев выгоднее, чем 10%.
Вашу точку зрения я понял, вместо аргументов по теме, оскорбления в адрес собеседника, удачи.
Не знаю, что мне делать с вашими молитвами. Вроде, я не отнимаю у вас GraphQL, не нужно так сильно переживать.
Хабр читают 10 млн человек, демагогию и троллинг нужно изобличать в явном виде.
Это у HTTP нет спецификаций?!

У HTTP есть. Но они оперируют понятием ресурса и его представления, не документируя управление его представлением. Максимум можно выбирать одно из доступных представлений. Грубо, HTTP специфицирует как получить JSON представления ресурса, но не позволяет регулировать какие поля включать в JSON, а какие нет.

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

Не согласен. Это формат запросов, прежде всего, в котором обязательноц частью является и спецификация формата ответа.


Если пишете сервер для GraphQL с нуля — все эти вопросы уже заложены в архитектуру, вплоть до выбора БД.

Пробовал. В экосистеме PHP поддержка GraphQL, особенно вкупе с SQL-базой оставляет желает лучшего. Подход "по единственному требующемуся API выбираем платформу влоть до СУБД" может и имеет право на жизнь в каких-то проектах, но на моей практике различных интерфейсов к одним и тем же данным/операциям множество, а тип СУБД или вообще её наличие определяется совсем по другим критериям чем простота/сложность прикручивания к ней конкретного API.

Уже не раз сталкивался с этой проблемой, разработчики не знают что такое REST и из-за этого делают уродливые апи с кучей лишних вызовов.
REST — это архитектура предпологающая клиент-серверное взаимодействие, БЕЗ хранения промежуточного состояния. Нет состояния, нет проблем, есть куча фишек вроде кеширования и слоистости. Это не про ресурсы /user:id user/:id/comment/:id, не про вербальность GET-PUT-DELETE… как думают многие и откуда растёт миф:
Пользоваться старой REST-моделью это как заказывать пиццу, затем заказывать доставку продуктов, а затем звонить в химчистку, чтобы забрать одежду. Три магазина – три телефонных звонка.

REST не запрещает тебе сделать метод POST /doMagic {pizza: {}, address: {}, tea: {}}, и если ты пошлёшь все необходимые данные, то он закажет пиццу, доставку и включит чайник. Отличие от классического подхода то, что ты не установил адрес доставки при регистрации пользователя, а при запросе взял его сс сервера, а отправляешь его явно на /doMagic в виде сырых данных либо идентификатора по которых его можно получить из стораджа (вреде userId).

Это к тому, что GraphQL тоже является REST подходом, просто у него апи не VERB resource/:id и вам никто не мешает делать такое апи. Например мы, посылаем декораторы, чтобы сказать какие поля получить
GET /user/:id?decorators=name,address,comments.count.
Не придумывайте себе исскуственных ограничений, которые не описаны в настоящем REST.
Все верно, GraphQL — логичное развитие не только REST, но и многих других (и OData и RPC). Здесь есть один нюанс, что промежуточного состояния как бы нет, но за счет графовой структуры мы можем состояние как бы «засунуть» на вершину, а потом по ребрам передать. А сейчас то же самое с последовательными запросами (batch) в рамках одного.
Главное отличие — велосипед написан, он вполне адекватен, выполняет все, что декларирует, зафиксирован, есть поддержка крупного вендора. Ну и удобный синтаксис, наверное, главное.

Всё же отстутствие промежуточного состояния лишь один из признаков REST. Другие важные в контексте поста и обсуждений — он оперирует идентифицируемыми ресурсами через их представления и гиперссылки.
GraphQL же в общем случае оперирует графами объектов.

Давно смотрю в сторону GraphQL, в REST бывает в напряг плодить эндпоинты, особенно в большом проекте, от документации которых бедный свагер распухает невероятно…

Но меня коробит от запросов вида

/graphql?query={ book(id: «1») { title, author { firstName } } }


А кто переживает по поводу избыточности количества запросов в REST: «отправь 10 запросов чтобы получить полную информацию для ItemID» — обычно добавляю еще 1 ендпоинт и композитор (ну я так называю, поправьте), композитор на ендпоинте в свою очередь визывает нужные методы и собирает данные, выдавая все 1 респонсом.

Все четко, понятно кто (ендпоинт) за что отвечает, никакой магии.

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

Но лично для меня так и не понятно, как же это все будет работать на стороне сервера.
В статье приведены два примера уровня Hello World, где все элементарно просто и красиво.

Но как это будет в случае, когда запрос должен будет выгребать данные из Реляционной СУБД (Postgres)?
К примеру все тот же элементарный пример: Books + Author + Comments.

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

А это значит, что нужно сделать 3 запроса к СУБД для того. Или это нормально?

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

+ А как работать в ситуации, когда у тебя часть данных должны придти с внешнего сервиса? к примеру: геолокация или какие-то инвентори/прайсы т.д.
Я получаю от ORM IQuerible и скорее всего могу сделав проекцию добавить туда еще что то не сломав при этом тот же пейджинг. Но не поручусь, нужно пробовать.
А это значит, что нужно сделать 3 запроса к СУБД для того. Или это нормально?

как хотите. Хотите 3 запроса, хотите 1 с джойнами, хотите orm воспользуйтесь. Собственно запросы пишете вы.

Отличный ответ из разряда: «Проблема на вашей стороне» ;-)

Конкретная проблема:
Есть Книги, есть Автора, есть Комментарии к книгам, все это в разных таблицах.
Через GraphQL делается 2 запроса на книгу с bookId:
1. запрос на книгу + автора книги
2. запрос на книгу + автора + комменты

Я вижу 3 варианта реализации на бекенде:
1. делать маппинг «в лоб» (как показано в статье), это будет 2 запроса к базе в первом случае и 3 во втором.

2. делать «оптимизацию», то получим 1 большой запрос и в маппинге просто результаты будем разгребать.
но в этом случае будет сложный запрос как в случае с комментами, так и без них. Это тоже плохо.

3. делать «по-умному», но это будет очень сложная логика по созданию запроса к базе, грубо говоря, нужно будет сделать конвертор «GraphQL to SQL» для конкретного проекта и любое небольшое изменение будет требовать большого объема работ.

Я не силен в GraphQL особенно со стороны бекенда, потому мне интересно: как это должно быть? Какой подход правильный?
Из всех статей про GraphQL я видел только радостные отзывы, как это удобно для фронтенда и ни разу не видел примеров как это выглядит со стороны бекенда.

Вы можете подсказать, как это должно быть на стороне бекенда? У вас есть с этим опыт?
Зависит от вашей СУБД, в общем случае, смотря, что выгоднее, так же, как и всегда.
2. делать «оптимизацию», то получим 1 большой запрос и в маппинге просто результаты будем разгребать.
но в этом случае будет сложный запрос как в случае с комментами, так и без них. Это тоже плохо.

Если это для вас плохо, а предыдущий вариант, например, медленный, просто не закладывайте в схему GraphQL таких возможностей. Опять же, GraphQL тут не причем, разделение нагрузки между клиентом и сервером задача каждого проекта.
3. делать «по-умному»,

Опять же, зависит от схемы, в данном случае схема может плясать от бэкенда, пойти по пути Rails и сделать автоматическую схему из моделей, со всеми методами (createModel1, updateModel1, deleteModel1), универсальными фильтрами (примерно, как в Mongo posts (filter:{ nameLike: «name» }) ), но с иерархической вложенностью. Такая схема не потребует для поддержки ни строчки кода. Только кастомные запросы, типа авторизации, остальное все автоматически, знай, модели добавляй. Тут пока готовых качественных решений нет, однако биндинги ко многим ORM уже существуют.
просто не закладывайте в схему GraphQL таких возможностей.
Спасибо, это уже звучит как ответ.

т.е. GraphQL подразумевает, что бекенд будет предоставлять какую-то конкретную схему ответа?
Если так, то это не сильно отличается от какого-то простого HTTP/WEB API, и отличие только в том, что в ответ приходит ограниченный набор данных.
Если так, то это не сильно отличается от какого-то простого HTTP/WEB API, и отличие только в том, что в ответ приходит ограниченный набор данных.

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

За то, чтобы фронтенд получал меньший объем данных, идет довольно высокая плата в виде QL в URI, а на бекенде и вовсе не понятно что получается. Либо это постоянно гоняется сложный запрос и выгребает все данные из базы и внешних сервисов, либо прячется за какой-то монстроузорный механизм по работе с базой, как кто-то говорил в этом треде, – адаптеры GraphQL к ORM.

По-моему, крайне небольшое преимущество. И скорее всего, это все будет работать хорошо только в случае: JS -> NodeJS + MongoDB, А в других случаях – от этой технологии будет больше проблем, чем пользы.

Но, поживем, увидим.
высокая плата в виде QL в URI

что за плата? что за проблема?


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

просто работа с базой. в /products?include=comments у вас как-то по другому будет или что?

что за плата? что за проблема?

Как минимум две:
1. Длина URI. Часто длина URL должна быть ограничена, я бы даже сказал, что это правило хорошего тона.
2. GET запрос с длинным query будет плохо кешироваться транслирующими узлами.
Веб это не только Клиент + Сервер, это еще десятки транслирующих и часто по совместительству кеширующих узлов.

просто работа с базой. в /products?include=comments у вас как-то по другому будет или что?

Да, будет по-другому.
Во-первых, не будет необходимости парсить GraphQL и писать свой «Query-engine» для доступа к данным.
Во-вторых, URI остается чистым и красивым (не будет проблем, описанных выше).

Вы можете считать, что это все надуманные проблемы. Но с другой стороны, GraphQL решает все те же надуманные проблемы типа «сложно расширить модель» или «слишком много данных передается в запросе» ;-)
Да, будет по-другому.
Во-первых, не будет необходимости парсить GraphQL и писать свой «Query-engine» для доступа к данным.
Во-вторых, URI остается чистым и красивым (не будет проблем, описанных выше).

вы ответили на цитату про работу с базой данных вещами, с базой данных не связанными.

Если про саму СУБД, то в случае HTTP/WEB API, это будет практически всегда один запрос к базе, он будет спроектирован так, чтобы из СУБД не вытаскивать ничего лишнего и чтобы вся агрегация выполнялась на стороне СУБД.

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

Ну, в целом, если плевать на то, как быстро будет работать сервер, и если идти по пути «плевать, докупим еще серверов» – да, это отличная технология. Разработка будет быстрой, проекты будут сдаваться быстро и в срок и все будет круто! =)

я же спросил: в /products?include=comments у вас как-то по другому будет или что?


один запрос у вас будет? два? три? почему в graphql другое кол-во запросов будет?


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

Вам так кажется, потому что вы не попробовали.

Грубо, в варианте /products?include=comments будет захардкожено что-то вроде


sql = 'SELECT * FROM product';
if (request.include === 'comments') {
sql = sql + 'INNER JOIN comments ON product.id = comments.product_id';
}

В варианте с GraphQL, пользуясь референсной или близкой к ней реализацией сервера подобное сделать будет сложнее. Хорошо если малой кровью получится сделать два запроса, а не 1+N

Грубо, в варианте /products?include=comments будет захардкожено что-то вроде

именно. если реализация graphql-сервера позволяет на уровне ресолвера узнать запрошенные поля, мы делаем точно так же.

Отличный ответ из разряда: «Проблема на вашей стороне» ;-)

graphql не предъявляет никаких требований к получению данных, только к структуре готовых данных в ответ на запрос.


Я не силен в GraphQL особенно со стороны бекенда

на бэкенде будет ресолвер query Books, который отдаст структуру с данными. Как вы эти данные получите, дело ваше (точно также как в jsonapi реализации /books/:id?include=author,comments). Если вас интересует как это можно сделать в различных языках программирования — это одно. Если в контексте graphql, то этот вопрос не имеет смысла.


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

потому что graphql (как и rest) про взаимодействие клиента с апи, а не про реализацию апи на бэкенде. Бэкенды реализуются по разному (можно взглянуть готовые либы на гитхабе).

  1. клиент -> 2. запрос -> 3. парсер запроса -> 4. мидлвари (авторизация, кэш, прочая инфраструктура) -> 5. ресолвер (обработчик конкретного типа запроса, извлечение данных) -> 6. Ответ

Вот типичный флоу, проходящий во время запроса на сервер. Пункты 4 и 5 не относятся к спецификации graphql, и могут реализовываться разработчиком на свое усмотрение.

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

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

у сервера GraphQL есть схема на все данные, клиент запрашивает данные согласно схеме (иначе ошибка валидации — вставить между 3 и 4 пунктами), сервер отдает данные согласно валидному запросу.
Итого: это язык общения между клиентом и сервером.

Вы можете подсказать, как это должно быть на стороне бекенда?

Имхо, нет единого "как должно быть"


У вас есть с этим опыт?

Помучавшись с GraphQL под PHP перешел от схемы GraphQL<->PHP<->Doctrine<->SQL к GraphQL<->NodeJs<->"REST"<->PHP<-><->Doctrine<->SQL

Вам не кажется, что если убрать GraphQL и NodeJs ваш API станет понятнее и проще?
GraphQL<->NodeJs<->"REST"<->PHP<-><->Doctrine<->SQL

"Web API"<->PHP<-><->Doctrine<->SQL
в данном случае, Web API делает все то же, что делал бы с GraphQL, только без «QL» в URI запроса.

Что вы имеете в виду под Web API?

У Вконтакте есть API вида:
/api/user.get?user_id=34124123&fields=name,age,email
/api/friends.get?user_id=34124123&limit=30

Это однозначно не REST, это некий HTTP/WEB API, альтернативно можно назвать RPC.

Ну, собственно, Facebook и предлагает GraphQL как один из инструментов создания и использования подобного API.

Фишка GraphQL в том что там один ендпоинт, т.е. одним запросом можно выташить не связанные данные, например для /api/friends.get запросить еще и 10 саммых популярных постов не будет очень логично
Как говорилось выше, не любые данные можно запросить, а лишь те, которые поддерживаются на стороне бекенда.

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

соответственно, если API изначально но поддерживает выборку постов для запроса на френдов, то и в выдаче их не будет.
соответственно, если API изначально но поддерживает выборку постов для запроса на френдов, то и в выдаче их не будет.

Да

Но и запрашивать 10 саммых популярных постов в /api/friends.get не будет очень логично
В этом случае будет создан другой эндпоинт, который будет отдавать френдов с их постами, который будет более логичным. Не так ли?

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

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

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

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


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

UFO just landed and posted this here

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

UFO just landed and posted this here

Допустим у вас есть ендпоинты /users и /posts, возврающие списки юзеров со списком айдишников постов и список постов с айдишниками авторов(юзеров). Фронт работает по схеме типа: берем список постов с сервера, из них выгребаем айдишник автора, и берем по нему ФИО автора с сервера. 10 постов показать надо — делаем 11 запросов. На уровне бэка это всё связано, но вот просто такие ендпоинты. Спецы по UX и фронтендеры посовещались и пришли к вам просить сделать новый ендпоинт /posts-with-authors. Знакомо? В случае GraphQL они к вам не пойдут, а сразу сделают, а ещё вероятне фроендерам сразу по рукам надают когда они 11 запросов сделают.

UFO just landed and posted this here
А если к постам нужны не только авторы, но и коментарии и профили коментаторов? Тоже все в /posts?
UFO just landed and posted this here
Когда вы отображаете Пост, что главное? Как можно быстрее отобразить сам контент этого поста, чтобы пользователь мог начать его читать.

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

Даже тут на хабре есть id, name, avatar коментатора
UFO just landed and posted this here
Хабр как пример что такой запрос нужен в реальных приложениях.
Комментрии тут, это часть контента, и их нельзя подтягивать, т.к. тогда поисковики их не проиндекируют. Так что не всегда возможно подтянуть данные.
UFO just landed and posted this here
Давайте смотреть от вариантов использования.

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

UFO just landed and posted this here
Так и в GraphQL продется писать отдельные query и имплементацию на бэкэнде.

Не совсем так. Грубо говоря, для GraphQL надо написать отдельный query для корней агрегатов, но не надо писать отдельные для "пост с авторами", "пост с комментариями", "пост и с авторами, и с комментариями".


Ну и да, пока что я вижу только одну фичу GraphQL — это отдать тлько те данные которые запросили, но это нужно только очень большим компаниям которым нужно экономить на трафике

Экономия трафика для моих проектов — бесплатный бонус. Основной плюс — не надо изменять бэкенд когда фронтенду нужно было 7 полей из 20 имеющихся в "базе", а теперь нужно 15. И если на плоских структурах можно просто отдавать все поля сразу, то на иерархических отдавать весь граф неразумно, а на циклических просто невозможно (в рамках JSON).


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

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


Мы это уже проходили, сначала все было в хранимках и были DBA, теперь их както меньше, все используют ORM.

Всю жизнь сам писал и хранимки, и "обычный" код. С приходом ORM в массы, хранимки, триггеры, вьюшки и т. п. пишу лишь в исключительных случаях, когда, они дают неоспоримое преимущество. Основная причина — SQL-логика сложнее в поддержке, прежде всего в плане инструментария.

UFO just landed and posted this here
Это не совсем бесплатный бонус, вы теряете возможность кэширования

Нашим процессам кэширование скорее противопоказано. Может, конечно, пользователь жать F5, но при нормальном флоу как раз постоянно происходят изменения состояния — суть пользовательских сценарие в изменении.


Про циклические данные я не понял, могли бы вы ткнуть меня носом как эта проблема (которой у меня не было) решается в GraphQL?

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


Почему вы предполагаете, что если GraphQL, то модели api у нас вседа идеальны и не требуют расширения или изменения, а если REST, то у нас все плохо?

Я предполагаю, что модели одинаковы, но в случае REST всё наружу не выведено через API в целях оптимизации трафика.


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

Как по мне, то ровно наоборот. REST хорош как раз для сохранения/синхронизаций состояний. Получил "снэпшот" ресурса по GET, что-то намодифицировал и отправил новый "снэпшот" по PUT или "дифф" по PATCH. GraphQL же как раз заточен (в плане модификации) под точечные бизнес-операции, позволяя избегать костылей типа POST /posts/123/approve c пустым телом.


Ну и опять же, один ресурс может отдавать разные модели, например:
/posts
может вернуть PostReference, Post, PostWithComments,
используя разные типы, такие как
application/vnd.post-ref+json, application/vnd.post+json и т.д.

Можно считать GraphQL более гибким и простым (как минимум на фронте) способом делать это.

UFO just landed and posted this here
Допустим у вас есть ендпоинты /users и /posts, возврающие списки юзеров со списком айдишников постов и список постов с айдишниками авторов(юзеров). Фронт работает по схеме типа: берем список постов с сервера, из них выгребаем айдишник автора, и берем по нему ФИО автора с сервера. 10 постов показать надо — делаем 11 запросов.

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

В крайнем случае, я бы сделал batch эндпоинты для получения данных:
/user/list?ids=1,2,3
/post/list?ids=1,2,3
в этом случае запросов будет всего 2.

Спецы по UX и фронтендеры посовещались и пришли к вам просить сделать новый ендпоинт /posts-with-authors. Знакомо?

К счастью в команде, где люди хоть чуть-чуть понимают что делают, такое бывает крайне редко.

В случае GraphQL они к вам не пойдут, а сразу сделают
В случае с GraphQL у них будут все те же /users и /posts, которые они смогут запрашивать через GraphQL. Ни один вменяемый бекенд девелопер и тем более архитектор (или тех.лид) не позволит сделать схему, в которой будут все возможные данные. Потому что эта херь сразу завалится при более-менее нормальной нагрузке.
UFO just landed and posted this here
При девелопменте используем любые запросы, на бекенде делаем в лоб.
На проде используем только предварительно одобренные запросы, которые уже можно оптимизировать так как запросы не могут быть любыми.
В результате у вас конкретный API, который мы можете дергать, он получается не такой уж и гибкий.
В чем тогда преимущество перед обычным «Web API»?
В девелопменте он гибкий и фронтенд не должен каждый раз просить бекенд добавить новые поля или новый ендпоинт
Учитывая, что бекенду нужно все так же делать маппинг и создавать все ту же схему данных ( как сказал zelenin в https://habrahabr.ru/post/335158/?reply_to=10351014#comment_10350990 ), то получается, что не так уж это и гибко, как вы говорите.

Если в модели нету дополнительных полей, бекенду нужно будет их добавлять (расширять схему).
Расширять схему надо будет намного реже, чем в REST или RPC добавлять новые ендроинты, так как часто нужны почти те же данные, соответственно для каждой комбинации по отдельному ендпоинту

Гибкий он ситуациях, когда модель данных покрывает бизнес-потребности, но на фронте полная модель не нужна. В традиционной модели два подхода основных:


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

GraphQL (а такжеJSON API и подобные стандарты) предлагают третий путь — клиент имеет доступ ко всей модели, но реально запрашивает только то, что ему нужно. Сказал бизнес "Вот в карточке продукта у нас есть поле "последняя дата входа в систему учетной записи пользователя, последний раз редактировашего продукт", добавьте его колонкой в список продуктов — бэкенд при этом не затрагивается, а объём передавемых данных был и остаётся близким к минимально необходимому (с учетом потребностей HTTP и JSON).

Коллеги, а правда написано вот в этой статье https://www.progress.com/blogs/rest-api-industry-debate-odata-vs-graphql-vs-ords что в GraphQL нет фильтрации?

Ну то есть что то в духе
GET serviceRoot/People?$filter=FirstName eq 'Scott'
GET serviceRoot/Airports?$filter=contains(Location/Address, 'San Francisco')

в graphql есть аргументы в запросах:


query {
  People(FirstName: "Scott") {
    .. // fields
  }
}

И как сделать возможность фильтрации по любому из 10 полей с любым из 10 предикатов (равно, больше, меньше, не больше, не меньше, между, включает и тд) с возможностью повторения полей (например, вхождение в один из нескольких диапазонов)?

согласно реализации. сама спецификация не описывает варианты использования артибутов.

Не уходите от ответа. Как такое можно реализовать? Свой язык запросов в параметре Filter?

я не ухожу от ответа — я прямо говорю: спецификация это не описывает.

Никаких проблем сделать это на GraphQL нет
query {
    People(
        Age: { and: [ { between: [15,16] }, {between: [20, 30] } ]  }
    )
}

Но делать что-то настолько универсальное нужно с очень большой оглядкой на бэкенд. Это удобно на этапе проектирования, но в production лучше уже нести более конкретную схему.

Спасибо, то есть аргументом может быть произвольный JSON. Не понятно тогда зачем было вводить множественные именованные аргументы, если можно было бы всегда принимать один аргумент JSON вида.

  1. это не json, а объект в терминах grapqhl
  2. аргументы разным целям служат, где-то фильттр, где-то сортировка, где-то служебный флаг итд. Вообще во всех языках в функции передается список аргументов, а не массив.

Речь о том, что можно было бы сделать так и не вносить лишних сущностей:


query {
    People({
        Age: { and: [ { between: [15,16] }, {between: [20, 30] } ]  }
    })
    Book(123)
}

ну в любом языке можно было бы сделать


func GetPeople(object)

вместо


func GetPeople(var1, var2, var3)

но семантика и все такое — поддерживается второй вариант, и в его рамках первый.

UFO just landed and posted this here
Я бы с удовольствием, но эта статья — перевод.
UFO just landed and posted this here
графкул очередной(внеочередной) посредник между серваком/клиентом. (лишний имхо)
непохож как данные хранятся на серваке ни как они нужны на клиенте, типа такой вот оригинально-абстрактный, его нужно выдумать/спроектировать, поддерживать отдельно от остальных.
читаем данные из нормализованной(или не очень, может вообще nosql) базы, пихаем все это в графкул, передаем на клиента и переделываем там в нужный по ему формат…

зачем вся это возня… и причем тут graph, с графами какая связь то?
По моему в подобных статьях часто путают, как выше в комментах писали, предлагают graphql как замену ресту, привычным ендпоинтам и т.п.,

А оно же из названия все понятно: data(graph) query lenguage.

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

Юзать графкл вместо обычного реста для апи среднего приложения, или пусть большого, где графами и не пахнет — это боль и ад… технология ради технологии для экономии на спичках

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

Да, похоже, большинство споров о хайповом продвижении GraphQL «для всего», а не об реальном использовании в конкретных задачах. Данная статья как раз такая — «почему технология А лучше технологии Б» вместо «в каких задачах и как удобно применять технологию Б».
А как там дела с ролями/правами на допуск?
Множество вещей, которые клиент не должен видеть, часто на основе ролей запрашивающего пользователя.

Как это задокументировать в GraphQL?
А как там дела с ролями/правами на допуск?

Так же как и в "REST" — всё на вашей совести

Ну, в документации REST API я могу указать какие права надо иметь для каждого ендпоинта, а тут только 1 ендпоинт, вот мне и интерестно как клиенты узнабю что нужны какие-то права если этого нет в документации?

в rest у вас эндпойнты, в graph — типы query/mutation и соответствующие им ресолверы.

Ну и как мне задокументировать что для какой-то коллекции нужны какие-то права?

а как вы в rest это делаете?

в документации REST API я могу указать какие права надо иметь для каждого ендпоинта

в документации GraphQL API укажите какие права надо иметь для каждого типа запросов

Супер, а как это сделать, есть какие-то тулзы? Для REST мы используем Swagger и там можно указать права.

не знаю, погуглите. это не часть спеки, как и не часть rest.

http://facebook.github.io/graphql/#sec-General-Principles
М, что-то не могу найти, какой пункт?
у graphql есть тулза (интерактивная документация) https://github.com/graphql/graphiql у ваших резолверов есть поле Description (если брать expressjs реализацию), туда и пишите вашу документацию
В восемьсоттридцатьчетвёртый раз:
  • REST = RPC — используем для вызовов методов API
  • OData/GraphQL = SQL — используем для запросов к данным


Поражаюсь стремлению людей усложнять понятные парадигмы.
В GraphQL есть мутации, т.е. не только запрашивать но и изменять данные
REST != RPC

RPC — удаленное выполнение некой логики. Грубо говоря — сервер, сделай там что-то и скажи что получилось.
REST — передача состояния между клиентом и сервером. не подразумевает каких-то тяжелых рассчетов. Грубо говоря — CRUD.

OData\GraphQL\FQL и т.д. — это только R из CRUD, который REST

GraphQL точно имеет поддержку всеможных мутаций, то есть встроенный механизм RPC именно в виде "сервер, сделай там что-то и скажи что получилось, причём скажи только интересующие нас здесь и сейчас детали, а не всё что ты можешь сказать по этому поводу".

Очевидно же, что ту имела ввиду не эквивалентность, а расположенность на одном уровне абстракций.

Очевиднейшая идея.
Тормозится исключительно отсутствием полных, удобных и популярных фреймворков для этого.
Ну ещё, возможно, отсутствием полной, быстрой и популярной объектной СУБД (реляционные — гениальная идея, но устарела N десятилетий назад).
Имхо, давать фронтендщикам (при всём огромнейшем уважении к ним) писать запросы к БД посредством GraphQL (в статье об этом ни слова но в конечном счёте это так), нужны очень веские основания для этого и соответствующий уровень фронтендщиков (которые понимают как работает бэкенд и база).
Идея, конечно, интересная, отдать все нужные фронтенду данные одним запросом. НО. Всегда ли это нужно? Когда меня об этом просят, я начинаю задавать уточняющие вопросы, и очень часто оказывается, что не так уж и нужно, просто чуть удобнее (или так кажется), зато часто будет большой оверхед по производительности на сервере и клиенте (да-да, в т.ч. в браузере, хотя я понимаю, что GraphQL изначально предназначен снижать оверхед, но это очень сильно от рук зависит).
В тех случаях, когда действительно нужно в одном запросе отдать связанные данные, ок — это не проблема и в обычном REST. Не отдавать не нужные данные — тоже при необходимости оптимизации траффика реализуется.
К тому же, когда GraphQL API доступно в мир, там реально могут легко атаковать твой сервер на отказ от обслуживания сложными запросами. Т.е. даже знание бэкенд-разработчиком ВСЕХ видов запросов, которые составляет фронт-енд, не спасёт.
Я конечно раньше про это не читал, и могу ошибаться, но пока с моей колокольни выводы такие, не судите строго.
Имхо, давать фронтендщикам (при всём огромнейшем уважении к ним) писать запросы к БД посредством GraphQL (в статье об этом ни слова но в конечном счёте это так)

нет, это не так


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

но не существует спецификации


К тому же, когда GraphQL API доступно в мир, там реально могут легко атаковать твой сервер на отказ от обслуживания сложными запросами

GraphQL не подразумевает сложных запросов. Он подразумевает язык общения между клиентом и сервером.

UFO just landed and posted this here
GraphQL не подразумевает сложных запросов. Он подразумевает язык общения между клиентом и сервером.
Таки это и подразумевает.
Вы пишите запрос к серверу «дай мне кучу данные вот таких и таких с такими фильтрами», и сервер начинает тужится выгребать и фильтровать их.
Сортировка и Группировка в GraphQL есть? – еще лучше, прям раздолье для повышенной нагрузки на сервер!

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

сервер начинает делать то же, чтобы делал в rest. Вы попробуйте уже наконец.


Сортировка и Группировка в GraphQL есть? – еще лучше, прям раздолье для повышенной нагрузки на сервер!

а в чем проблема? конечно есть, как и везде.


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

согласно спецификации. провалидировать, вернуть ошибки.

> сервер начинает делать то же, чтобы делал в rest. Вы попробуйте уже наконец.

В общем случае — нет, REST «заставит» вас правильно разложить персистентные модели на ресурсы для быстрой их отдачи, «естественным» образом подтолкнёт к реализации соответствующей денормализации данных и инкапсуляции всех долгих агрегаций и вычислений за ресурсами типа «операция». Да, это требует больше усилий в проектировании, а GraphQL позволяет заняться этим позже, но этим заняться всё равно придётся (если проект «выстрелит», да, потому для прототипирования MVP для привлечения первичных инвестиций, наверное, GraphQL хорош).

> а в чем проблема? конечно есть, как и везде.

Это примерно как вместо бэкэнда просто расшарить клиентам БД и заниматься композицией данных на клиенте. Кажется поначалу неплохой идеей (экономия на бэкенде, пусть фронтендщики и гуй рисуют, и данные себе структурируют), но в итоге приводит к «отсутствию» архитектуры.

если проект выстрелит, то у меня будет денормализованное хранилище, а не sql с join'ами.
Опять обсуждаем хранилище в обсуждении языка запросов.

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

мной тоже.


И, главное, вы поняли точку зрения?

конечно понял — вы в очередной раз обсуждаете то, что к graphql не относится.


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

эти сложности не являются следствием использования graphql, и аналогично присутствуют (и решаются) в rest. Вот что оппоненты не хотят видеть, поскольку 99% не поняли что это такое, и как вообще это работает, хотя демки с кодом гуглятся на раз-два.

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

какие эти проблемы? которые с graphql не связаны? прикрутить авторизацию? кэширование? проверка на уровни вложенности? как все это сделает из graphql rest?


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

не надо говорить за оппонентов — никто из критиков здесь не то, что не решал, а даже не трогал graphql на деле.

REST — это архитектурный паттерн (даже мета-архитектурный — это набор ограничений для построения собственной архитектуры), накладывающий ограничения и на протокол, и на представление API сервера (в виде ресурсов с фиксированным набором действий над ними), и обосновывающий это всё математикой (сокращением вероятности неконсистентных между собой состояний клиента и сервера и увеличением контроля над этими ситуациями). REST — это «инструкция» по тому, как строить веб-приложение. А GraphQL — это способ не забивать себе этим всем голову, а просто расшарить БД фронтендеру. И по мере усложнения композиций данных, собираемых на клиенте, сталкиваясь с проблемами обеспечения актуальности и непротиворечивости разных кусков моделей, неявно собираемых бэкендом с GraphQL, а может и пытаясь горизонтально отмасштабировать проект, программист так или иначе придёт ко всем тем проблемам, которые и решались Филдингом в его диссере о REST. GraphQL — это способ пройти путь Филдинга, набив собственные шишки, но зато очень быстро начав, сразу с готовой библиотеки с низким порогом вхождения (и раньше получив видимый результат для инвесторов). GraphQL — это способ экономить большим корпорациям, уменьшая требования к квалификации программистов (и это не оскорбление, это то, к чему стремится каждый программист — упрощение своей работы). Это не плохо или хорошо, это просто иной подход, в какой-то ситуации он может быть и оправдан (например, если вы — Facebook с штатом на триллион программистов, или если прототипируете MVP, или вам ну просто по каким-то причинам недоступен отдельный квалифицированный бэк-программист).
А GraphQL — это способ не забивать себе этим всем голову, а просто расшарить БД фронтендеру.

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


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

> Это попытка переиначить язык запросов между клиентом и сервером для упрощения этого взаимодействия.

Вы как бы кратко прорезюмировали всё то, что я написал в предыдущем комментарии :).

> опять же не вижу аргументации, кроме общефилософских измышлений

Да, потому что и проблема «философская» (о способах построения архитектуры и ограничениях, которые помогают это сделать, либо эти ограничения можно будет вывести самостоятельно, описывая взаимодействие между клиентом и сервером более «вольным» языком GraphQL и не понимая, почему в одном месте страницы, например, обновился счётчик, а в другом нет, и лишь затем придя к необходимости выделения отдельной репрезентации «страница такая-то», а не неявной её сборки из кучи персистентных моделей, которые клиенту вообще не должны быть видны).

> Если есть что-то конкретное сказать, давайте общаться — у меня реальные проекты и на rest и на graphql.

О чём общаться? Какую конкретику вы имеете ввиду? Тут проблема в общем подходе, а не в отдельных сравнениях каких-нибудь параметров запросов или способах масштабирования, просто перекладывание части бизнес-логики на язык запросов между клиентом и сервером. (Не абсолютная проблема, а, скорее, особенность, GraphQL — просто инструмент сокращения количества архитектурных слоёв в приложении путём «ленивого» проектирования этих слоёв «потом»).

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

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

вы в итоге получите REST, без всех гибкостей
Не совсем. GraphQL в общем случае можно считать надмножеством REST, как его классически реализуют; всё то, что можно получить при REST, позволяет и GraphQL; но GraphQL позволяет на ходу строить и более сложные запросы. Да, бо́льшая часть гибкости GraphQL окажется невостребованной, но не вся.
> Не совсем. GraphQL в общем случае можно считать надмножеством REST

REST и RPC взаимовыразимы друг через друга, но являются принципиально различными подходами к проектированию API.

> всё то, что можно получить при REST, позволяет и GraphQL

Всё то, что можно получить при Haskell и C++, позволяют и ассемблер или машинные коды.

> Да, бо́льшая часть гибкости GraphQL окажется невостребованной, но не вся.

Например?
нет, это не так
Значит я что-то не так понял из статьи (да, я не пробовал GraphQL). Но я и не осуждаю данный подход (как кто-то мог подумать), в своих ситуациях вполне может подходить. Как идея, он мне даже нравится.
Я про тот случай, когда ко мне приходит фронтендщик, мол, мне нужен такой ендпойнт с такими-то данными (как пример, список постов и для каждого список ВСЕХ комментариев, пример вполне реальный, названия сущностей изменены, но суть та же, лимитирование, пагинация — нет, не слышал). И если у него будет возможность построить самому такой запрос с помощью GraphQL, я не смогу его отговорить, я об этом просто не буду знать. Опять же, если я что-то не так понял, прошу прощения.
С другой стороны, если уровень бекенд разработчиков недостаточен, чтобы построить более-менее нормальную REST архитектуру (с учётом всех пожеланий), то особой разницы может и не будет. Поэтому, повторюсь, в конечном счёте больше зависит от рук, нежели от технологии.
И если у него будет возможность построить самому такой запрос с помощью GraphQL, я не смогу его отговорить, я об этом просто не буду знать.

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


При такой схеме комменты вытащить нельзя:


type Post {
name: String
}

type Comment {
body: String
}

query GetAllPosts {
Posts: [Post]
}

При такой можно:


type Post {
name: String
comments: [Comment]
}

type Comment {
body: String
}

query GetAllPosts {
posts: [Post]
}
Спасибо за пояснение.
Благодаря ему, даже глянул, какие есть библиотеки на php.
Ну и демагогию развели, половина претензий к GraphQL — это недопонимание, остальное — троллинг. Думаю, если каждый скептик уделит время написанию простого API с использованием этой технологии, появится возможность обсудить что-то насущное, а не переливать из пустого в порожнее.
UFO just landed and posted this here
так вперед простой Конкретный пример показать, чтобы появилась эта возможность

фейсбук как пример не катит
А Github?
https://developer.github.com/v4/
ссылка на доку Introduction to GraphQL…
разговор же о конкретном примере, где лучше юзать графкул, или все пока только на доки могут ссылаться.

Как раз на простом особо не вылезут ни недостастки, ни преимущества. Простой API, аналогичный типичному REST-подобному с парой ендпоинтов, покажет небольшие преимущества для фронта и немного увеличившуюся сложность для бэка. А основные преимущества GraphQL лежат, имхо, в приложениях со сложной моделью, а основной недостаток — слаборазвитая экосистема для бэкендов, особенно не в JS+Mongo мире.

Думаю, преимущества еще будут сильные в потоковой передаче данных (aka, директивы live, stream, defer и т.д.)
А в качестве сомнений, наоборот можно отнести запоздалое решение по объединению нескольких запросов в один. С приходом http2 — это скорее минус, чем плюс, выгоднее данные грузить параллельно.
Самое главное преимущество прямо исходит из названия — графовое представление данных.
Вообще, все идет по спирали, начинается с примитивов, потом появляются более сложные конфиги, переменные, условия, потом язык конфигураций, а дальше язык программирования.
Вот и передача данных дошла до этапа сложных, но пока еще декларативных языков, насколько этого хватит, по мне, так уже не хватает, в том же вконтакте, как пример, есть метод execute.

Кстати, относительно сильных сторон REST, кэширования и проксируемости, тут вся фишка в идентификации ресурсов, а не в этой архитектуре. А если у нас есть идентификаторы, то и для любых других систем это возможно. Еще вопрос, насколько это востребовано, каков реальный процент использования HTTP-прокси-кэша с учетом https.
Я как backend-developer скажу, что пишу на graphql проекты уже 2 года, написали свой порт на php — https://github.com/Youshido/GraphQL. Когда у тебя много клиентов, то польза от него просто вау. Хотите узнать в чем идея, читают не данную статью, а посмотрите видео с презентации команды facebook почему они его придумали — коротко и ясно и так сказать в лицо.

знатакам rest: как потянуты три картинки аватарки в одном запросе?

{
  me {
    id
    firstName
    lastName
    small: image(width: 100, height: 100, mode: INSET) { // resized directly
      url
    }    
    medium: image(width: 500, height: 300, mode: OUTBOUND) { // different mode
      url
    }    
    fullSize: image {
      url
    }
  }
}

Реально большую работу проделали. Спасибо.


Долго пытался внедрить ваш порт в свои проекты, но в результате только там, где не требуется работать со сложными БД осталось :( Как вы решаете задачи связи GraphQL с SQL-базами, или, как вариант, Doctrine? Или таких нет в ваших проектах?

видео с презентации команды facebook

Можно ссылку пожалуйста?
UFO just landed and posted this here
если вы такие умельцы портируйте на PHP jsonnet ( jsonnet.org ) .GraphQL будет отдыхать. А пока да он весьма неплох.

но это как бы разные вещи — язык запросов для api и шаблонизатор для json.

UFO just landed and posted this here

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

Explain GraphQL like I'm five.
https://dev.to/johnpaulada/explain-graphql-like-im-five
If GraphQL servers are only going to accept pre-approved queries, that defeats the whole point of GraphQL
https://www.reddit.com/r/reactjs/comments/5aemkc/if_graphql_servers_are_only_going_to_accept/

Почему вы сравниваете язык запросов (GraphQL) с архитектурным принципом (REST), а не с другими языками запросов (OData, SparQL, Gremlin, json:api)?

https://jrgql.github.io/ a GraphQL alternative
Sign up to leave a comment.

Articles