Как стать автором
Обновить

Комментарии 41

А есть ли какие-либо данные по производительности такого решения?

Можете посмотреть по ссылке на live demo в разделе CI/CD.


Всё запущено на e2-small GCE инстансе. Под нагрузкой не пробовал, сейчас показывает:


Красиво, и подписки есть, не хватает только блокировок для полного счастья.
Очень крутая статья хоть и не пишу на раст.

ЗЫ вообще чем больше смотрю на graphql тем меньше понимаю почему рест еще не сдох.

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

Потому что graphql кривой и ряд вещей без бубна в нем не делаются?

Уточните, пожалуйста, пару моментов:


  • "кривая" спецификация GraphQL или какие-то из реализаций на конкретных языках? Если второе, то на каких именно?
  • "ряд вещей" — можете привести пару примеров?
Сама идеология.

Имеются проблемы с гранулярностью контроля доступа к данным.
С нормальным кешированием.
Да и rate limit в рамках его идеологии ложится из рук вон плохо.

P.S. И да, у REST своего… хватает. Но поскольку он чуть ниже уровнем, то жить с этим чуток проще.

Я не считаю идеологию кривой. Запрашивать ровно те данные, которые нужны клиенту, при меньшем количестве сетевых запросов — вполне нормальный подход. Может наоборот, REST кривой в этом аспекте?


По поводу примеров:


  • если я правильно понял "гранулярность доступа", то с этим всё ок. Сама спека ничего не говорит об этом, при этом конкретные реализации могут имплементировать данную функциональность. Что и было показано в статье (раздел "Авторизация"), когда для мутации определён "гард". Аналогично гард может быть указан для любого поля какой-либо структуры. В других фреймворках это будет реализовано по-другому
  • кэширование — не знаю, что вы имеете в виду. Вот пара ссылок: eng/ru, судя по которым не кажется, что кэширование в GraphQL — это rocket science. Да, сделано по-другому, чем в REST, но это ведь не значит криво?
  • rate limit — сходу не нашёл примеров реализации, но стоит отметить, что эта проблема не столь актуальна как в REST. В GraphQL вызовы одной и той же query могут содержать разные наборы полей, поэтому большее значение имеет возможность ограничения глубины и сложности запроса, что, полагаю, реализовано в большинстве GraphQL библиотек и также было показано в статье
Начнем со второй части.

если я правильно понял «гранулярность доступа», то с этим всё ок.

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

Кеш в целом для graphql сложнее. У вас нет никаких гарантий что в рамках одного и того же запроса даже с одинаковым unique ID, как рекомендуют по вашим ссылкам, у вас будут одинаковые структуры и одинаковый набор полей (вы ведь при запросе их указываете).
Можно делать прегенерированные запросы с гарантированным набором полей (это, кстати, решает и вопрос доступа) и кешировать их, но это превращает всю идеологию graphql в тыкву.
github.com/apollographql/persistgraphql
Правда не знаю что сейчас актуально вместо этого решения, а искать лень.

rate limit — сходу не нашёл примеров реализации,

Они есть, но там тоже ничего приятного.

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

Идеология graphql в инверсии контроля, а не «запрашивать те данные которые нужны».
Вы перекладываете контроль за тем что и как вам нужно на строну клиента.
Пока у вас приложение внутреннее — все ок.
Как только вы интерфейс выставляете наружу, то выясняется что доверять клиенту нельзя. Отсюда и вопрос доступа, и вопрос лимита на запросы и т.п.

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

И, да, это не значит что я за REST. Мне он не нравится лишь немногим меньше чем graphql.
Как разумную альтернативу здорового человека я предлагаю использовать RPC и его вариации в виде JSON-RPC, XML-RPC, gRPC.

У него есть минусы.
  • вы должны предусмотреть варианты запросов заранее (но смотрим persistgraphql)
  • вы будете медленнее вносить изменения потому что они должны будут сделаны и на клиенте и на бекенде.


Но при этом.
  • У вас сохраняется возможность запросить ровно те данные, которые нужны на клиента.
  • У вас нет проблем присущих graphql с доступами и ratelimit.
  • У вас нет проблем излишней абстрактности REST, который вынуждал дробить запросы.

Там зубодробительная логика на стороне бекенда получается.

Это ваш личный опыт реализации GraphQL API или в вашей компании? Дело в том, что множество материалов, включая прочитанную (?) вами настоящую статью, это не подтверждают


Идеология graphql в инверсии контроля, а не «запрашивать те данные которые нужны». Вы перекладываете контроль за тем что и как вам нужно на строну клиента.

Это вольная трактовка или есть источники/ссылки, подтверждающие что это и есть иделогия?


Вы перекладываете контроль за тем что и как вам нужно на строну клиента.
Пока у вас приложение внутреннее — все ок.
Как только вы интерфейс выставляете наружу, то выясняется что доверять клиенту нельзя. Отсюда и вопрос доступа, и вопрос лимита на запросы и т.п.

"GraphQL позволяет клиенту выбирать нужные ему данные с точностью до полей, но при этом всё ещё нужно обеспечивать безопасность приложения" — no comment


Как разумную альтернативу здорового человека я предлагаю использовать RPC и его вариации в виде JSON-RPC, XML-RPC, gRPC.

Как разумный здоровый человек я воздержусь от обсуждения RPC как способа frontend-backend взаимодействия в комментариях к статье "GraphQL на Rust"


Доп. вопрос: какую библиотеку вы использовали для реализации GraphQL API?

Дело в том, что множество материалов, включая прочитанную (?) вами настоящую статью, это не подтверждают

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

Почему бы это вдруг?

Hint: включите свои гварды на запрос с 3-4 join/subselect обеспечив ограничение области видимости отдельных полей для разных пользователей и не запрашивая их у БД, если пользователю они не доступны по контексту данных (ой да, бывает и такое).

Это вольная трактовка или есть источники/ссылки, подтверждающие что это и есть иделогия?

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

Доп. вопрос: какую библиотеку вы использовали для реализации GraphQL API?


graphql-php
и уже не помню что на стороне nodejs в качестве api gateway. Емнип что-то из apollo, но это не точно, давненько было.
Чем вам это поможет в бессмысленных попытках натянуть сову на глобус?

По запросу «graphql drawbacks» гугл выдаёт почти то же самое, что привели вы. Совпадение?

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

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

Я правильно понял, что у вас не получилось реализовать GraphQL API в рабочем проекте без проблем с перформансом?


Это то, что содержится в вашем же определении выделенном кавычками.

Так вы же попытались там опровергнуть моё определение, предложив своё. Вот мне и стало интересно, откуда оно?


Чем вам это поможет в бессмысленных попытках натянуть сову на глобус?

О чём вы?


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

Где вы увидели обвинение? Я только уточнил

Я правильно понял, что у вас не получилось реализовать GraphQL API в рабочем проекте без проблем с перформансом?

Я правильно понимаю что у вас нет внятной аргументации и ответов и поэтому вы пытаетесь о чем-то догадаться?

Так вы же попытались там опровергнуть моё определение, предложив своё. Вот мне и стало интересно, откуда оно?

Оно не мое. Это прямо следует из вашего определения.

Если дверь открывается, но ее открывали не вы, то это сделал кто-то (или что-то) отличное от вас.

Это прямо таки рокетсайнс?

О чём вы?

О вашей идее что graphql это серебрянная пуля, подходящая везде всегда и вообще наилучшее решение.
Ведь именно это вы пытаетесь протолкнуть не сумев опровергнуть ни одного из замечаний, ссылаясь исключительно на «там кто-то написал».
Я правильно понимаю что у вас нет внятной аргументации и ответов и поэтому вы пытаетесь о чем-то догадаться?

Нет, вы ошибаетесь, аргументация есть. Оптимально, когда задаваемые вопросы касаются темы статьи ("GraphQL на Rust"). Также по мере возможностей отвечаю на более абстрактные вопросы, в том числе совпадающие с поисковой выдачей гугла по запросу "graphql drawbacks"


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

А вот это уже клевета. Не уверен, что это разрешено правилами сайта

Оптимально, когда задаваемые вопросы касаются темы статьи («GraphQL на Rust»).


Повторюсь.

Hint: включите свои гварды на запрос с 3-4 join/subselect обеспечив ограничение области видимости отдельных полей для разных пользователей и не запрашивая их у БД, если пользователю они не доступны по контексту данных каждый 5й день недели (ой да, бывает и такое).

Вперед.
Повторюсь.

Это совсем не обязательно. Ваши кейсы здесь никому не интересны

По запросу "graphql drawbacks" гугл выдаёт почти то же самое, что привели вы. Совпадение?


Поддерживаю оратора выше а так же замечу что rest api вот уж точно кривой и точно ряд вещей без бубна не делаются.

REST проще, GraphQL нужен для моделей типа FB, а таких в природе немного.

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

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

Каким образом в GraphQL гарантировать, что через апи нельзя выбрать лишнего

А что вы понимаете под "выбрать лишнего"? В моём понимании это гарантирует синтаксис. В статье есть пример запроса:


{
  getPlanets {
    name
    type
  }
}

В ответ на это GraphQL сервер пришлёт исключительно 2 запрашиваемых поля для каждого элемента возвращаемого списка.


запросы, которые получаются не уложат базу

Для этого есть несколько инструментов:


  • ограничение сложности и глубины запроса
  • решение проблемы N+1
  • пагинация (для query, возвращающих массивы/списки с большим количеством элементов, создайте параметры pageNumber, pageSize)

Первые два вопроса освещены в статье. Да и в целом по ним достаточно материала


Если есть простой способ этого добиться

Имплементация вышеуказанного — в целом решаемая задача

А что вы понимаете под "выбрать лишнего"?

Попросить


{ blog { published_posts { author { posts } } }

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


ограничение сложности и глубины запроса

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

Я бы предложил поменять схему данных, после чего запрос станет:


{
    getPosts(filter: {status: PUBLISHED}, page: {number: 1, size: 10}) {
        author {
            name
        }
    }
}

Далее, предположим у кого-то появится желание положить сервер таким запросом:


{
    getPosts(filter: {status: PUBLISHED}, page: {number: 1, size: 10}) {
        author {
            posts {
                author {
                    posts {
                    # и т. д.
                    }
                }
            }
        }
    }
}

Предотвратить такую циклическую цепочку вызовов невозможно, если только не поменять типы, удалив поле Author.posts или Post.author.


Поэтому первое с чего стоит начать — это ограничение глубины запроса (разумеется, GraphQL, а не SQL. В качестве хранилища может быть что угодно: SQL, NoSQL, in-memory и т. д., о чём GraphQL знать не нужно). В данном простейшем случае можно установить его например 3, чего должно быть достаточно для получения всех нужных данных. Соответственно, клиенту при выполнении запроса выше придёт сообщение о его невалидности.


Также можно указать, что поле Author.posts принимает аргумент количества постов, тогда запрос станет:


{
    getPosts(filter: {status: PUBLISHED}, page: {number: 1, size: 10}) {
        author {
            posts(first: 10) {
                title
            }
        }
    }
}

Вроде обращение Author.posts и избыточно, но по крайней мере не критично для перформанса.


Если этих простейших шагов окажется недостаточно, то можно использовать более продвинутые техники (например, Query Cost Analysis) (см. https://www.apollographql.com/blog/securing-your-graphql-api-from-malicious-queries-16130a324a6b/ и другие источники).

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


  1. Не положит базу.
  2. Не вытащит чего-то, чего юзеру видеть нельзя.

В REST есть похожие проблемы, но их масштаб, кажется, значительно меньше.

Спасибо, что представили существо вопроса


  1. Используйте все указанные выше подходы
  2. Изучите документацию к выбранному фреймворку и используйте представленные там подходы к security
Идем сюда — cve.mitre.org/cgi-bin/cvekey.cgi?keyword=GraphQL и смотрим первые 10 уязвимостей. Видим, что 6 из них это про получение или модификацию данных, которые получить и модифицировать нельзя (CVE-2021-22863, CVE-2020-6165, CVE-2020-26417, CVE-2020-26415, CVE-2020-26413, CVE-2020-2640). Занавес. Похоже у ребят из Gitlab, Github и SilverStripe активно наступают на грабли, о которых я говорю.
Нет не проще когда вы доходите до подписок и селективности свойств, а вы до них в любом случае дойдете.
Мне в соседней ветке никак не могут объяснить как защититься от проблем с тем, что через GraphQL неожиданно можно получить данные, которые получать не следует? С учетом мощности языка это кажется очевидной проблемой. И не только мне, тут видно, что из первых десяти уязвимостей шесть про получение или модификацию данных, которые получить и модифицировать нельзя (CVE-2021-22863, CVE-2020-6165, CVE-2020-26417, CVE-2020-26415, CVE-2020-26413, CVE-2020-2640).
ACL на уровне резолверов раз.
ACL на уровне БД — два, причем тут с гарантией, в PG вы можете что на столбцы что на строки задавать уровень доступа. Соответственно как минимум две разные учетные записи в бд вам создать ничего не мешает.
У той же hasura.io насколько я помню сразу есть неплохой acl.
ACL на уровне БД не очень выразительны, тяжеловато будет сказать что-то вроде — «можно читать юзерам из группы А, а также тем, у кого в таблице X есть запись Y».

ACL на уровне резолверов это хорошо, только проблема не в том, что нельзя ограничить. Проблема в том, что модель могут запрашивать миллионом разных способов, из которых 999 990 разработчику неизвестны, он о них не подумал, о них подумает хакер, что подтверждается статистикой по уязвимостям. Я не вижу никаких простых решений, кажется все что есть это
1. Сесть и продумать все возможные сценарии, подкрепить это кучей тестов.
2. Сделать плоскую модель ala REST, в которой и так все очевидно. Скорее всего это значит, что доставать author.posts уже не стоит, потому что кто знает, что через post[1] можно вытащить еще.

PS: Забавно, даешь людям ссылки, где черным по белому показано — из-за обсуждаемой проблемы уязвимости есть даже у крупных организаций. Отмечу, что крупняк то как раз имеет средства и время чтобы best practices применять, чего не всегда можно сказать о стартапе. Но нет, карма потихоньку сливается и сливается, похоже читатели не верят, что проблема есть.
ACL на уровне БД не очень выразительны

вполне выразительны

тяжеловато будет сказать что-то вроде — «можно читать юзерам из группы

легко

А, а также тем, у кого в таблице X есть запись Y».

ненужно

Проблема в том, что модель могут запрашивать миллионом разных способов, из которых 999 990 разработчику неизвестны

ограничения ему заранее известны.

Я не вижу никаких простых решений, кажется все что есть это

А я вижу

2. Сделать плоскую модель ala REST, в которой и так все очевидно. Скорее всего это значит, что доставать author.posts уже не стоит, потому что кто знает, что через post[1] можно вытащить еще.

Вы привыкли что вы в рест сыпете все всегда и всем, а теперь тонкая настройка пошла, ну и что? ACL расставить по полям не есть проблема. Еще раз, вворачиваете ACL в резолвер — все.

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

А люди вам отвечают что это все решаемо, а вы опять в теорию.

Отмечу, что крупняк то как раз имеет средства и время чтобы best practices применять, чего не всегда можно сказать о стартапе.

Как раз у крупняка обычно пароли 123456 на базы данных и прочая ересь. А стартап подобного головотяпства себе позволить не может.

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

Читатели не считают ее нерешаемой
ненужно

Ну раз вы так сказали, значит ненужно. Зачем вы тут вообще на меня время тратите? Идите лучше консультантом в Gitlab и расскажите им как нужно ACL в резолверах крутить, они похоже там очень тупых программистов нанимают, которые неспособны такую фигню осилить. Но вы то сможете, у вас best practices и статьи о том, как все хорошо в GraphQL.

Эка вас сплющило, как скажете, это очень сложно, осилить невозможно, ок.

Вы путаете «сложнее чем REST и ведёт к вполне реальным проблемам, у которых нет простых решений» и «осилить невозможно». И это действительно сложно, сложность формата входных данных как аргумент и список CVE как факт. Все что вы можете на это ответить это «они все дебилы, я знаю как, вот вам ACL». Только проблема к ACL отношения не имеет. Удачи.

Читал я вас читал, так и не понял что вы пытались донести. Да мы в курсе, да мы знаем. Хотите рассказать как вы правы с дивана? Ненужно, верим.
Элементарно Ватсон, читаем что написано — «REST проще, GraphQL нужен для моделей типа FB, а таких в природе немного.»
И вы эту мантру нам решили втолкать насильно чтоле? Нет, простите, живите с ней сами.

Как всегда, после любой статьи про graphql одни и те же комментарии про "не нужно", и минимум комментариев про саму статью.

Работают ли подписки, если публикумые данные собираются с нескольких бэкендов? Сможет ли сервер федерации обработать такой кейс?

минимум комментариев про саму статью.

К сожалению, да, большая часть комментариев не имеет отношения к теме статьи


Работают ли подписки, если публикумые данные собираются с нескольких бэкендов? Сможет ли сервер федерации обработать такой кейс?

Apollo Gateway не поддерживает подписки: https://github.com/apollographql/federation/issues/426


Мне известно о следующих альтернативах Apollo Gateway:



Разработчиками первых двух заявляется, что они поддерживает подписки; последняя не поддерживает (https://github.com/nautilus/gateway/issues/108)


Планирую заменить Apollo Gateway в проекте на GraphGate, как только (или если) он станет production-ready, и протестировать указанный кейс


Полагаю также, что от всех указанных альтернатив следует ожидать заметно большую производительность по сравнению с Apollo Gateway

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории