

Dmitri
14.06.2018
18:57:54
GraphQL это язык, на котором клиент обращается к серверу. Тебе, как разработчику API, нужно написать переводчик GQL в данные, как ты это сделаешь уже другой вопрос.
У нас слоистая архитектура такова:
1. transport (transmit, authenticate) - отвечает за передачу данных и аутентификацию клиента, может быть HTTP(s), может быть WS(S), в нашем случае это https://github.com/qbeon/webwire-go
2. graph (parse, validate, authorize) - отвечает за парсинг, валидацию и авторизацию. Вызывает resolver функций для каждого поля графа. За парсинг у нас отвечает библиотека https://github.com/graph-gophers/graphql-go, а авторизация происходит в самих resolver функциях на основе тех данных, которые нам 1 транспортный уровень передал о клиенте.
3. loaders (batch, cache) - отвечает за batching и caching, грубо говоря на этом слою устраняются лишние engine-call'ы, если какие-то entity уже имеются в кэше или уже запросились другим resolver'ом, то мы его не дублируем
4. engine interface (engine capabilities) - это абстрактный интерфейсный уровень. Каждая реализация движка сервиса должна полностью воплощать этот интерфейс
5. engine (business logic, databases) - отвечает за бизнес логику и работу с бд, обязан полностью воплощать интерфейс. У нас обычно 2 движка: mock & production, mock тупо в памяти, production на основе какой-либо бд
Graph Query Language - язык запросов для использования исключительно настоящими аристократами-графами.
Я про то говорю, что, из аналогий, которые в голову приходят, допустим, из java. Есть StreamAPI - это GQL, и есть умелка ручками сделать prepared-запрос в БД - это рест-подход. Вот второй случай имеет бОльший ресурс оптимизации
Или из паттернов: repository vs dao = gql vs rest


Roman
14.06.2018
18:59:35
наивная реализация GQL, где у нас запрос в бд в самом резолвере может обернуться катастрофой. Например представим кейс, где нужно запросит 100 пользователей и 100 друзей каждого из них.
query {
users(limit: 100) {
id
firstName
lastName
friends(limit: 100) {
id
firstName
lastName
}
}
}
В наивной реализации у нас получится 100 * 100 = 10.000 запросов на бд, а это катастрофа, это одним запросом валит API.
если же написать с 3ей прослойкой loader, то всё это превратится в 2 round-trip'а на бд, первый качает пользователей, второй - их друзей.
т.е. resolver'ы обращаются к loader'у и просят вернуть им пользователя Х, loader аккумулирует все запросы и в конце 100 резолверов превращаются в 1 список id'шников пользователей, который легко обрабатывается любой бд. loader по истечению 10 мс вызывает engine.getUsers(ids) и разблокирует все резолверы вернув каждому запрошенного пользователя, потом вызываются уже резолверы друзей, и в лучшем случае, у многих юзеров будут совместные друзья и loader устранит лишние повтряющиеся id, а уже считанных пользователей возьмёт из кэша.


Dmitri
14.06.2018
18:59:55
И вот не всегда и не во всех случаях какой-то из подходов гарантированно лучше

Google


Roman
14.06.2018
19:02:13
наивная реализация GQL, где у нас запрос в бд в самом резолвере может обернуться катастрофой. Например представим кейс, где нужно запросит 100 пользователей и 100 друзей каждого из них.
query {
users(limit: 100) {
id
firstName
lastName
friends(limit: 100) {
id
firstName
lastName
}
}
}
В наивной реализации у нас получится 100 * 100 = 10.000 запросов на бд, а это катастрофа, это одним запросом валит API.
если же написать с 3ей прослойкой loader, то всё это превратится в 2 round-trip'а на бд, первый качает пользователей, второй - их друзей.
т.е. resolver'ы обращаются к loader'у и просят вернуть им пользователя Х, loader аккумулирует все запросы и в конце 100 резолверов превращаются в 1 список id'шников пользователей, который легко обрабатывается любой бд. loader по истечению 10 мс вызывает engine.getUsers(ids) и разблокирует все резолверы вернув каждому запрошенного пользователя, потом вызываются уже резолверы друзей, и в лучшем случае, у многих юзеров будут совместные друзья и loader устранит лишние повтряющиеся id, а уже считанных пользователей возьмёт из кэша.
с рестом таких проблем не возникает. просто пишем запрос и достаем нужные данные


Roman
14.06.2018
19:03:09

Dmitri
14.06.2018
19:04:36

Roman
14.06.2018
19:04:37

Nick
14.06.2018
19:04:46

Roman
14.06.2018
19:05:56
полный контроль

Dmitri
14.06.2018
19:06:00
В случае Реста вы подходите к проблеме со стороны планирования потребительских запросов, в случае gql - со стороны организации данных

Nick
14.06.2018
19:06:14

Roman
14.06.2018
19:06:23
Кроме gRPC
что REST, что gRPC это формы RPC
a RPC это такой-же tight-coupling, который мне лично уже так осточертеть, что я решил нехило так рискнуть и перейти на совершенно иной подход, т.е. GQL

Nick
14.06.2018
19:06:26
Можешь тоже сам все написать

Roman
14.06.2018
19:07:14

Roman
14.06.2018
19:07:15

Google

Dmitri
14.06.2018
19:08:04

Nick
14.06.2018
19:08:07

Roman
14.06.2018
19:08:47

Nick
14.06.2018
19:09:21
Ещё удобно микросервисам дальше прокидывать

Dmitri
14.06.2018
19:09:48
Вопрос в том, что при изменении сущности на бэкенде в случае реста клиенты не отвалятся. С gql - вполне себе слохнут

Roman
14.06.2018
19:10:01

Anton
14.06.2018
19:10:03
а такой тогда вопрос - swagger платный?
если на свой сервер

Nick
14.06.2018
19:10:14
Ничего не путаешь?)

Roman
14.06.2018
19:13:22
Ещё удобно микросервисам дальше прокидывать
вы сами пробовали? во всех проектах, где я работал, в этом не было бы особого смысла. конечно, когда зоопарк языков и 100500 разных инстансов, этот уровень абстракции сыграет положительно. но таких проектов немного

Dmitri
14.06.2018
19:13:23
В смысле?
Ну вот есть у тебя табличка А и связанная с ней табличка Б. В какой-то момент ты рвешь реляционную связь между ними и втыкаешь туда табличку В. Т.е. связь получается А->В->Б. В этот момент gql побуждает переписать запросы на клиентах, рест - клиенты и не в курсе, ничего не ломалось


Roman
14.06.2018
19:15:02
Ну вот QueryLanguage - это про планирование иерархии данных. RPC - про планирование запросов клиента.
совершенно верно.
И так сложилось, что я столько времени постоянно тратил на написание новых endpoint'ов, что в один прекрасный день я сказал: "ребята фронтендеры, идите-ка вы все нах@й, я увольняюсь, я заебался постоянно изменять и проверять API по любому изменению UI".
GQL мне лично позволил написать 1 API, который можно использовать как угодно, без особых потерь производительности. Да, я потратил уйму времени, чтобы понять как правильно реализовать граф, но теперь сам для себя понимаю, что оно того стоило, что лучше таки 1 раз написать правильно и херачить потом запросы как угодно...
ну блин.. это все-равно что вам пришлось бы переписывать бд каждый раз когда меняется API, ну это же п@зд€ц, не зря же изобрели SQL, чтоб можно было 1 раз написать нормальный движок и не париться вообще что там нужно API'шке, что нужно то и запросит.

Nick
14.06.2018
19:15:19

Anton
14.06.2018
19:16:09
и самодокументируемость и сразу же типизация на фронте через flow к примеру


Dmitri
14.06.2018
19:18:39
совершенно верно.
И так сложилось, что я столько времени постоянно тратил на написание новых endpoint'ов, что в один прекрасный день я сказал: "ребята фронтендеры, идите-ка вы все нах@й, я увольняюсь, я заебался постоянно изменять и проверять API по любому изменению UI".
GQL мне лично позволил написать 1 API, который можно использовать как угодно, без особых потерь производительности. Да, я потратил уйму времени, чтобы понять как правильно реализовать граф, но теперь сам для себя понимаю, что оно того стоило, что лучше таки 1 раз написать правильно и херачить потом запросы как угодно...
ну блин.. это все-равно что вам пришлось бы переписывать бд каждый раз когда меняется API, ну это же п@зд€ц, не зря же изобрели SQL, чтоб можно было 1 раз написать нормальный движок и не париться вообще что там нужно API'шке, что нужно то и запросит.
Просто вы так рьяно отстаиваете позиции gql на мотивации "лично мне вкатило", при том, что на него никто и не нападал... GQL - вполне себе норм инструмент, никто и не против. Но на своем круге задач. Не стоит обливать грязью старый добрый rpc, основываясь на своем узком опыте.


Igor
14.06.2018
19:19:25
совершенно верно.
И так сложилось, что я столько времени постоянно тратил на написание новых endpoint'ов, что в один прекрасный день я сказал: "ребята фронтендеры, идите-ка вы все нах@й, я увольняюсь, я заебался постоянно изменять и проверять API по любому изменению UI".
GQL мне лично позволил написать 1 API, который можно использовать как угодно, без особых потерь производительности. Да, я потратил уйму времени, чтобы понять как правильно реализовать граф, но теперь сам для себя понимаю, что оно того стоило, что лучше таки 1 раз написать правильно и херачить потом запросы как угодно...
ну блин.. это все-равно что вам пришлось бы переписывать бд каждый раз когда меняется API, ну это же п@зд€ц, не зря же изобрели SQL, чтоб можно было 1 раз написать нормальный движок и не париться вообще что там нужно API'шке, что нужно то и запросит.
Так а вы на изменения UI переписывали endpoint-ы? Ну понятно, что есть перформанс и т.д., но говорить, что это был REST...


Nick
14.06.2018
19:19:27

Roman
14.06.2018
19:19:43

Dmitri
14.06.2018
19:21:03

Google

Nick
14.06.2018
19:21:08
Это контракт, который не обязан отражать то, что у тебя в базе

Roman
14.06.2018
19:21:53

Roman
14.06.2018
19:22:45

Dmitri
14.06.2018
19:22:53

Roman
14.06.2018
19:22:57


Subbotin
14.06.2018
19:23:21
совершенно верно.
И так сложилось, что я столько времени постоянно тратил на написание новых endpoint'ов, что в один прекрасный день я сказал: "ребята фронтендеры, идите-ка вы все нах@й, я увольняюсь, я заебался постоянно изменять и проверять API по любому изменению UI".
GQL мне лично позволил написать 1 API, который можно использовать как угодно, без особых потерь производительности. Да, я потратил уйму времени, чтобы понять как правильно реализовать граф, но теперь сам для себя понимаю, что оно того стоило, что лучше таки 1 раз написать правильно и херачить потом запросы как угодно...
ну блин.. это все-равно что вам пришлось бы переписывать бд каждый раз когда меняется API, ну это же п@зд€ц, не зря же изобрели SQL, чтоб можно было 1 раз написать нормальный движок и не париться вообще что там нужно API'шке, что нужно то и запросит.
Ну понятно. Переложил работу на фронтендеров

Nick
14.06.2018
19:23:42

Mykyta
14.06.2018
19:24:00

Roman
14.06.2018
19:24:05

Nick
14.06.2018
19:24:31

Dmitri
14.06.2018
19:25:15

Roman
14.06.2018
19:27:27

Dmitri
14.06.2018
19:27:57

Subbotin
14.06.2018
19:29:11

Dmitri
14.06.2018
19:29:19

Nick
14.06.2018
19:29:37
Я ж сказал

Dmitri
14.06.2018
19:29:42

Google

Roman
14.06.2018
19:30:41

Nick
14.06.2018
19:31:41

Roman
14.06.2018
19:31:49

Dmitri
14.06.2018
19:32:08
Надеюсь, хотя бы с тем, что GQL хочет бОльшего от архитектуры приложения, чем rest, который можно прикрутить по-быстрому сбоку, спорить не будете?

Roman
14.06.2018
19:32:23

Roman
14.06.2018
19:32:27

Nick
14.06.2018
19:33:24

Roman
14.06.2018
19:33:40

Artem
14.06.2018
19:33:58
Я честно не люблю gql, но с точки зрения контракта он хорош

Nick
14.06.2018
19:34:24
Единственная проблема, которую я вижу, это то, что паф один и нельзя монтировать на балансерах на разные сервера

Admin
ERROR: S client not available

Nick
14.06.2018
19:34:38
Все остальное - более менее решается

Dmitri
14.06.2018
19:34:47

Nick
14.06.2018
19:34:49
Естественно все зависит от либы, в го не пробовал

Roman
14.06.2018
19:35:15

Dmitri
14.06.2018
19:35:23

Roman
14.06.2018
19:36:37

Dmitri
14.06.2018
19:36:41

Google

Nick
14.06.2018
19:38:39

Roman
14.06.2018
19:40:53
Gql тож быстро прикручивается, прекрати выдумывать не существующих проблем
это неправда. GQL сложнее в реализации нежели REST.
поднять нормальный GQL наверное в 2 если не 3 раза было сложнее чем REST, но это при учёте что я поднимал первый свой GQL и библиотека реализации ещё немного сыровата, поэтому сравнение немного нечестное конечно.
Но даже сейчас, я бы не поднял GQL API быстрее чем REST, ибо просто совершенно другой подход...
в REST'е ты решаешь конкретные проблемы, а потом меняешь по мере изменения клиента
в GQL ты изначально пилишь "generalized solution", т.е. сложную, но очень гибкую архитектуру и тебе не придётся изменять API, если требования клиента(ов ) изменятся


Dmitri
14.06.2018
19:41:36
эээм, и чем тут REST отличается от GQL? оба принципа являются абстракциями... если бд изменится, то GQL остановится прежним, просто затронутые resolver'ы перепиши, как и endpoint'ы REST'а
Смотри, GQL - это про "отдать реляции наружу, пусть клиент сам определяет, что ему нужно". При наличии реальной реляции A->В->Б делать еще одну "виртуально-костыльную" А->Б для какого-то особого случая "чтобы не поломалось" хоронит нахрен всю красоту подхода GQL. В конце концов, ты граф замыкаешь... Ну и нафига? Просто ты озадачиваешь клиентов "мы тут поменяли, перепишите", и все - это верный подход GQL. Если "мы тут поменяли, перепишите" по какой-то причине "совсем-совсем нельзя", дважды подумай, прежде чем на GQL переползать.

Roman
14.06.2018
19:41:40
однако всё может поменяться. По мере становления GQL стандартом может появиться много готовых-из-коробки решений, которые значительно упростят постороение API такой архитектуры

Dmitri
14.06.2018
19:42:20

Artem
14.06.2018
19:42:32
В графкуэле в симфони покрайне мере, очень большой оверхед на проссчет ненужный данных, в го это надеюсь в готовых решениях не так заметтно

Dmitri
14.06.2018
19:43:45

Roman
14.06.2018
19:44:06
да и моделировать API на нём мне понравилось больше, но это отдельная, долгая тема

Dmitri
14.06.2018
19:45:25

Nick
14.06.2018
19:46:19

Roman
14.06.2018
19:48:02
Смотри, GQL - это про "отдать реляции наружу, пусть клиент сам определяет, что ему нужно". При наличии реальной реляции A->В->Б делать еще одну "виртуально-костыльную" А->Б для какого-то особого случая "чтобы не поломалось" хоронит нахрен всю красоту подхода GQL. В конце концов, ты граф замыкаешь... Ну и нафига? Просто ты озадачиваешь клиентов "мы тут поменяли, перепишите", и все - это верный подход GQL. Если "мы тут поменяли, перепишите" по какой-то причине "совсем-совсем нельзя", дважды подумай, прежде чем на GQL переползать.
я предпочту:
once in a while {
api -> N clients: I've changed, please update
}
нежели:
every fucking iteration {
N clients -> api: my data requirements changed, please fulfill my needs
}


Dmitri
14.06.2018
19:49:00
с этим я согласен. Но мой личный опыт сложился именно так, что приложения очень сильно и часто мутируют в процессе естественной эволюции и написав эти 20 RPC-методов, ты их потом ещё 100500 раз перепишешь/удалишь/создашь ибо требования, по крайней мере у меня, менялись так часто, что мне было выгоднее потратить гораздо больше времени на изучение графовой теории, но раз и навсегда научиться делать более сложные, но более устойчивые к изменениям требований API
там вся приколюха именно в том, что с GraphQL ты ИЗНАЧАЛЬНО моделируешь ГРАФ ДАННЫХ, чтобы потом с ним работать. В REST ты изначально моделируешь запросы клиента, а потом "откуда-нибудь берешь данные". Скажем так, на старте реализация от "начал" до "получил какой-то эффект" в REST'е быстрее, и не говорите мне, что это не так. Вопрос исключительно в том, на каком пороге они сравняются по трудозатратам, и на каком моменте GQL "окупится".
Вот реально, в стабильных апишках на пару-тройку эндпоинтов с 3-4 методами на каждый ты GraphQL не окупишь.


Nick
14.06.2018
19:49:56
На основании чего вывод


Dmitri
14.06.2018
19:51:35
У гитхаба чёт не возникло проблем)
ну вот теперь сравни гитхаб и openweathermap. Гитхаб - программистско-ориентированная хрень, обвешанная миллионом фич и хотелками миллионов пользователей. OpenWeatherMap - тупая апишка, отдающая данные из одной таблички по запросам на 3 эндпоинта, рассчитанная на энтузиастов и не-программистов... Веришь, что GQL погодным энтузиастам не нужен?

Nick
14.06.2018
19:52:20
Верю что его там можно юзать

Dmitri
14.06.2018
19:53:13
Да откуда такая метрика про быстрее?
давай на скорость: берем БД с одной табличкой, Go, и проверяем, кто быстрее напишет реализацию 1 метода апи с предопределенной выборкой. Я - с 1 REST-endpoint'ом, или ты с GraphQL?

Nick
14.06.2018
19:53:39

Dmitri
14.06.2018
19:54:07
Верю что его там можно юзать
чтобы энтузиасты гидрометеорологии изучали GraphQL, и заодно похоронили свои тысячи-их девайсы по сливу данных в апишку?

Nick
14.06.2018
19:55:04
Вижу совсем не понимание с твоей стороны. Ты хоть юзал графкуэль в проде?

Roman
14.06.2018
19:55:07
Вот тебе пример, где GraphQL "нивзлитит". Возьми вещи вроде OpenWeatherMap. Вот отдают они REST, и все довольны. Возьмутся поднимать GQL - и всем будет плохо.
ну они могут так-же с REST перейти на gRPC и так-же всё поломать, всем будет плохо, следственно gRPC говно? Странное причино-следственное мышление.
а вот тебе шах: возьмут они и случайно, предположим по ошибке, поменяют структуры данных, которые возвращаются REST Endpoint'ами и все клиенты накроются медным тазом, будет хаос, война, кровь и свидетели иеговы на каждом углу.
в GQL такое не прокатит, схема является контрактом. А контракт незаметно нарушить нельзя ни на сервере ни на клиенте.