Когда мы используем REST, GraphQL или RPC API из внешнего интерфейса, большую часть времени эти вызовы api просто переводятся в операторы SQL на внутреннем интерфейсе.

Так почему бы нам просто не написать SQL в интерфейсе для начала?

Я серьезно.

Чтобы приложение работало быстро, нам обычно нужен нормализованный кеш во внешнем интерфейсе. Когда мы начинаем пытаться делать оптимистичные обновления, все очень быстро усложняется. Если наша модель данных внешнего интерфейса точно не соответствует нашей модели внутреннего интерфейса, нам придется выполнить кучу причудливых обновлений кеша вручную. Просто ознакомьтесь с руководством Apollo по оптимистичному пользовательскому интерфейсу - оно интенсивно! Swr и response-query также оставляют вам ручное аннулирование запроса и обновление кеша.

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

Подумайте обо всем коде, который вы обычно пишете для обработки ответов API во внешнем интерфейсе. Обычно я получаю кучу Lodash (groupBy, filter, map, reduce), чтобы формировать данные, которые я получаю с сервера. Это всегда становится громоздким, и мне всегда хочется просто использовать SQL.

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

Мы можем получить все данные для представления одним запросом:

Если вы добавляете новую задачу в проект, вам необходимо обновить счетчик проектов на боковой панели. В идеале вы просто хотите добавить новую сущность «Задачи» и связать ее с проектом. Это одна строка SQL.

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

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

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

Почему это не было сделано?

Раньше нам говорили, что наши API должны быть REST. Вот что мы сделали.

Затем GraphQL освободил нас от REST и сказал: можно снова выполнять RPC для одной конечной точки. И у одних и тех же людей был свой протокол, так что мы и сделали.

Но теперь, когда можно снова выполнять RPC, возможно, мы сможем завершить цикл, и снова станет нормальным выполнение… SQL… как мы это делали, когда создавали настольные приложения.

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

Как это будет работать?

У нас уже есть SQLite в браузере через wasm, который мы могли бы использовать для этого. Однако чистая реализация SQLite JS была бы крутой.

Нам нужен ограничительный синтаксический анализатор SQL для запуска на стороне сервера, чтобы ограничить то, что можно запускать, и предотвратить SQL-инъекцию. Возможно, нам нужен построитель запросов / ORM для создания безопасного промежуточного языка SQL в JSON, чтобы мы могли его проверить. Возможно, черпая вдохновение в типобезопасном клиенте отображения данных Prisma, можно было бы использовать его, чтобы помочь людям писать безопасные запросы, которые не будут неожиданно давать сбой при проверке на стороне сервера.

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

Для мутаций, поскольку они довольно опасны и требуют тщательной проверки, мы могли бы вернуться к REST, мутациям GraphQL, RPC. Если нет большого значения в разрешении массового INSERT / UPDATE в качестве подзапроса SELECT, вероятно, лучше не отправлять их на стороне сервера и использовать их только для обновления нашей локальной модели данных.

Интересно

Возможно, SQL мог бы стать нашей унифицированной моделью данных, если бы мы могли заставить расширение-оболочку внешних данных Postgres работать в браузере, обертывая LocalStorage, API-интерфейсы расширения Chrome, IndexedDB и т. Д. Даже, возможно, сторонние API-интерфейсы - аналогично тому, как работает федерация GraphQL. .

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

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

Возможно, такие вещи, как SSR и PJAX, будут означать, что мы меньше полагаемся на состояние на стороне клиента в будущем, а обновления пользовательского интерфейса будут приходить в виде HTML поверх WebSockets или чего-то в этом роде.

Могут ли все данные пользователя быть представлены единой синхронизированной с базой данных SQLite интерфейсом / серверной частью, которую можно загрузить, чтобы обеспечить полностью автономную работу или функцию извлечения данных?

Возможно, мы могли бы также изучить локальное состояние как SQL, а-ля Apollo local-state.

Другие подходы

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

Что-то кроме SQLite. Печально, что WebSQL исчез, но, как я недавно слышал, как Джейк Арчибальд упомянул в эпизоде ​​подкаст JS Jabber, что было бы лучше, так это API-интерфейс хранилища на уровне байтов, чтобы люди могли реализовать свои собственные эффективные механизмы SQL в браузере.

Почему сейчас?

SQL сегодня повсюду. Все инструменты без кода включают SQL. Google Таблицы, Airtable, Retool. Лучший способ развязать свободу действий ваших сотрудников - это предоставить им доступ к вашим данным через SQL. Все этого хотят. Вот почему существует так много новых инструментов.

SQLite слишком часто упоминается в последнее время, и это одна из причин, по которой я подумал об этом. Если большему количеству людей это удобно

Мысли?

Что мне не хватает? Я очень хочу поиграть с этим, чтобы увидеть, работает ли это, потому что одно можно сказать наверняка: то, как мы в настоящее время делаем оптимистичные обновления пользовательского интерфейса с помощью Apollo и response-query, неприемлемо.

Обсуждение HN: https://news.ycombinator.com/item?id=26822884