Pull to refresh

Comments 35

UFO landed and left these words here

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

Но… разве это не ошибка бэка, такое обращение к базе?

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

Не совсем понимаю, в чем проблема? Стало интересно, какая у вас БД и сколько записей.

Проблема в механизме SQL offset limit. Чтобы выбрать, например, последние (по произвольному критерию сортировки) 100 записей из 100500, нужно выбрать 100500, отсортипрвать и показать, начиная со 100401

Ну так «последняя страница» ни при чем. Если есть любая пейджинация, то активно листая (или вбив руками номер страницы) у пользователя остается возможность завалить вашу систему, разве что вероятность меньше. Возможно, стоит тщательней продумать систему хранения данных (например, обязательный параметр фильтрации и секционирование по нему и т.д.) или кеширования.

Есть пагинации лишенные этой проблемы, там offset заменен на where

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

ЗЫ: Насчёт «другого способа нет» — можно как минимум не выкидывать результаты «прочитали, отсортировали», а оставить их для последующих запросов. Неважно как, хоть в базу обратно записать, уже с индексом по соответствующему полю.
Это далеко не всегда реализуемо. Если у запроса есть хотя бы несколько фильтров (особенно, по произвольной строке) и типов сортировок, то результаты запроса хранить не практично, т.к. количество вариантов запросов стремится к бесконечности.

Не говоря уже о том, что если хранить результаты запросов паджинации, то встает очень сложная проблема, как эти производные данные синхронизировать с основной таблицей, т.е. когда инвалидировать этот кэш.
Ну это всё опять же не проблемы фронта. Если бек такой, что по техническим причинам его можно вычитывать только потоком, то там по определению нельзя будет «запросить последнюю страницу». Если же такой запрос возможен — то он должен приемлемо работать.
Бек должен работать даже при х10 критической нагрузке. Если запросов больше, чем он может обработать — устанавливают лимит, который ставит запросы в очередь или вообще закрывает с ними соединение. Лучше пусть сервис работает для 50% пользователей, чем не работает вообще или уйдет в цикл когда новых запросов больше, чем можно обработать и все запросы будут возвращать ошибку(не хватит ресурсов на другие процессы).

А кто еще долбит api с большей частотой, чем нужно для нормальной работы сервиса, можно прописать бан на 10-15 мин или час.

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

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

Бэкэнд и фронтенд должны использовать соответствующие HTTP статусы

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

А какими были бы ваши советы к фронтендерам, что нужно знать о бекенде?

Советов много. Но я так понимаю, вопрос был риторический и с намеком?

Мои советы бы были такие:


  • Уметь понимать ООП. Это важно, чтобы понимать на основе каких моделей сделан бэкэнд и каковы принципы его логики. Изначально, кажется, никакого отношения между ними нет. Но вот мне не раз доводилось видеть, что UX рисуется наизнанку, где старшие по уровню представления находятся внутри, а младшие наоборот. Потом, соответственно, очень дорого платить за переделку.
  • Важно понимать, как на бэкэнде работает OAuth. Вряд ли без этого можно имплементировать его на фронте.
  • Нужно уметь запустить бэкэнд локально (на выбранных бэкэндами технологиях, которых может быть много) на случай, если прорабатывается конкретная версия бэка, не доступная на общих стэндах. Например, попытка воспроизвести какой-то конкретный баг с конкретными версиями бэка и фронта.
  • Еще надо знать объем функционала по версиям бэка, чтобы обращаться по правильным раутам типа /api/v1.2.3/users
  • Надо знать, как именно работают websockets на стороне бэка, чтобы их правильно имплементировать (sockejs — не вебсокеты, а раппер, который скрывает имплементацию и люди не понимают, что делают, постоянно дергая бэкэндеров).

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

Просто нужно различать статус уровня HTTP как транспортного протокола и статус обработки запроса приложением. Если сервер вообще не может понять, что с запросом делать, разобрать его, отроутить, то 4хх вполне уместны. Или если реальный HTTP REST решили делать, а не типа самописного RPC c HTTP в качестве транспорта. GraphQL — определенно вторая категория :)

а не типа самописного RPC c HTTP в качестве транспорта. GraphQL — определенно вторая категория :)

Вообще-то, первая. GraphQL (кроме сабскрипшенов) — ни что иное, как чистейший HTTP REST, только урезанный до одного метода POST. Никаких там самописных RPC нет.
Вы, наверно, перепутали GraphQL и gRPC.

Вы бы хоть определения почитали для начала.
В HTTP RESTful API POST-запросы создают новый ресурс, возвращая его URI. Что-что вы там создаете, отправляя graphQL-запрос?

Самое грустное, что людей, свято уверенных, что REST — это «HTTP-запросы фигачить» с каждым годом всё больше. И это даже несмотря на то, что REST это совсем не обязательно HTTP-запросы.
В HTTP RESTful API POST-запросы создают новый ресурс, возвращая его URI. Что-что вы там создаете, отправляя graphQL-запрос?

Это не так. Создать новый ресурс — это договоренность поверх даже 7-го уровня стэка OSI. Это не протокол вообще. Сделайте диссект протокола, увидите, что там этого нет. Хотите я вам по GET создам энтити? Хотите по POST верну что-то существующее заранее, не создавая ничего нового? Хотите префлайт на DELETE? Легко! Протокол не запрещает.


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

Я этого не говорил. Не понимаю, какое это ко мне имеет отношение. Зато суждение о моем тексте хорошо показывает ваш уровень квалификации.


Еще раз: GraphQL для квери и мутаций использует POST. Хотите вы этого или не хотите. А POST есть только у HTTP — опять же, хотите вы этого или не хотите. Никаких других протоколов там не задействовано. И стейта между запросами нет. Значит REST. Хотите вы этого, опять же, или не хотите.
И никакого самописного RPC там нет и в помине.

отите я вам по GET создам энтити? Хотите по POST верну что-то существующее заранее, не создавая ничего нового? Хотите префлайт на DELETE? Легко! Протокол не запрещает.

HTTP не запрещает. REST — запрещает. То, что у вас есть что-то, что кушает HTTP-запросы и что-то делает в ответ — не даёт вам право называть это RESTful API.

REST — это не протокол, а архитектура, если что.

Зато суждение о моем тексте хорошо показывает ваш уровень квалификации.

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

Я не очень понимаю, то вы хотите доказать.
Вы хотите сказать, что VolCh прав и под GraphQL писали свой RPC?
Или вы хотите сказать, что он не прав, там чистый HTTP, но не REST-compatible?


REST — это не протокол, а архитектура, если что.

Ни то ни другое. Это констрейнты, если быть точным. И я нигде не называл REST протоколом.

Вы хотите сказать, что VolCh прав и под GraphQL писали свой RPC?

Разумеется он прав. GraphQL не имеет никакого отношения к архитектуре REST. Это протокол запросов, в основном (но не обязательно) работающий через транспортный протокол HTTP.

Другое дело, что вы зачем-то придумали свой собственный вывод. «Под GraphQL писали свой RPC» — это ваши личные фантазии из солянки терминов, в посте VolCh написано совсем иначе — «типа самописного RPC c HTTP в качестве транспорта». Подумайте, почему его вариант — вполне нормальный, а ваш — нет.

Это констрейнты, если быть тончным.

Это архитектура.
Другое дело, что вы зачем-то придумали свой собственный вывод («под GraphQL писали свой RPC» — это ваши личные фантазии из солянки терминов).

А теперь послушаем VolCh:


Или если реальный HTTP REST решили делать, а не типа самописного RPC c HTTP в качестве транспорта. GraphQL — определенно вторая категория :)

Ну-ка повторите еще раз, что это моя фантазия.

когда вы шлёте HTTP POST запрос на /graphql с GraphQL запросом в теле вы по сути используете RPC over HTTP. где-то внутри HTTP-хэндлера осуществляется вызов GraphQL хэндлера, процедуры, а HTTP-хэндлер предоставляет возможность её удаленного вызова, remote procedure call, RPC

GraphQL не имеет никакого отношения к архитектуре REST

Какой из 6-ти констрейнтов нарушает GraphQL, что становится REST non-compatible?

Пардон, написал не так: GraphQL конечно же REST-совместим, но HTTP-endpoint (вебсервис или что угодно), работающий с GraphQL, не является RESTful.

У вас может быть самописный RPC, внутри себя соответствующий REST, но точка приёма этих RPC-запросов не будет соответствовать REST.

Я так понимаю, у вас какое-то свое определение RESTful.
Что это и чем это слово отличается от REST?

Я так понимаю, у вас какое-то свое определение RESTful.

С чего вы это решили?
RESTful = соответствующий REST. Только и всего.

Тогда как можно понять фразу:


GraphQL конечно же REST-совместим, но HTTP-endpoint (вебсервис или что угодно), работающий с GraphQL, не является RESTful
Ровно так, как написано. Речь про разные уровни транспорта. Там, где вы полностью абстрагировали всё, что ниже GraphQL — у вас REST-совместимый язык запросов, всё хорошо. Там, где вы работаете с нижележащим HTTP — у вас уже не REST.

1) GraphQL вообще язык запросов, хоть по email отправляете запросы и ждите ответа. На практике нередко работает исключительно по вебсокетам. Встречал даже непосредственно в rabbitmq запросы шли по вебсокетам, а сервер слушал и туда же ответы отправлял.
2) "дефолтная" имплементация GraphQL нарушает семантику HTPP как протокола прикладного (7-го) уровня OSI, используя его подмножество лишь в качестве транспортного, в том числе через POST для запросов, что не даёт использовать инфраструктуру кэширования HTTP, а кэширование неотъемлемая часть REST.

Sign up to leave a comment.

Articles