Деджаваскриптизиция (3)
Сбылась мечта идиота: теперь на сайте работают комментарии без строчки кода на Джаваскрипте. Смотайте экран вниз, там форма. Требуется только имя и тело комментария. Ввели, отправили, и через некоторое время он появится в блоге.
Форма:
Экран возврата:
А что, мне нравится.
Расскажу, как это работает. В прошлый раз я перенес комментарии Disqus в репозиторий. Каждый комментарий — это файл формата YAML + markdown. В числе прочего он хранит ссылку на пост. Когда я собираю блог, в подвал каждой заметки подставляются ее комментарии.
Для приема комментариев я следую тому же принципу: чтобы они появились на сайте, нужно создать файл в репозитории. Теоретически любой может оформить pull request, но это сложно. Должен быть сервис, который преобразует ввод пользователя в pull request для блога. Этот сервис я написал и назвал blog-backend.
Сервис напоминает веб-приложение: оно принимает HTTP-запрос с формой. После прелюдии с валидацией перехожу к главному: интеграции с Гитхабом. Это оказалось не так-то просто. У Гитхаба уже три рестовых API, но ни одно не покрывает все возможности. Кроме REST есть убер-апишка на GraphQL — она-то мне и нужна.
Интеграция с GraphQL была нелегкой: это самобытный язык и вещь в себе. Если бы в текущем проекте не было GraphQL, я бы полез на стенку. Во-вторых, сложность процесса: чтобы сделать PR силами API, нужно четыре вызова:
- получить метаданные репозитория, в том числе последний коммит;
- создать ветку от этого коммита;
- сделать коммит в новую ветку;
- сделать PR.
Как по мне, апишка не консистентна: где-то на репозиторий ссылаешься по имени, а где-то по машинному ID, который приходит из метаданных. То же самое с ветками: где-то имя, где-то айдишник. Ответы GraphQL развесистые, с глубокой вложенностью. Например, последний коммит ветки погружен на пять уровней:
(-> resp-get-repo :data :repository :ref :target :oid)
С такой апишкой невозможно программировать без образца данных.
Когда подружился с Гитхабом, настала проблема хостинга: где и как размещать логику. Мне понравился опыт с облаком Яндекса, и я продолжил эксперименты. Сервис написан на Кложе, скомпилирован Граалем в бинарь и хостится в Яндекс.Функции — аналоге AWS Lambda.
В свою очередь, Яндекс.Функция — это облачный сервис, где размещают какой-то код и дергают его по запросу. Отличие от обычного хостинга в том, что у лямбды нет состояния: она запускается на короткое время и умирает. В зависимости от окружения лямбда может умереть не сразу, и если ее дернуть повторно, сработает уже запущенный экземпляр. На базе этого делают “прогрев” лямбд, у которых окружение стартует медленно, например Java. В моем случае граальный бинарник быстрый как не весть что, прогрева ему не надо.
Лямбду можно вызывать разными способами, в том числе HTTP-запросом. У каждой лямбды свой урл, который может быть приватным и публичным. Его можно указать в разных сервисах, что отлично подходит для ботов.
По сравнению с VM-хостингом у лямбды следующие плюсы:
- не нужна виртуальная машина и ее настройка;
- не нужен домен;
- лямбды экстремально дешевы, потому оплачивается только время работы с округлением до 0.1 секунды;
- лямбды поощряют писать код без компонентов и состояния, что как бальзам на душу после проектов по работе.
Поначалу я был крайне скептичен к лямбдам, но теперь вижу в них особую прелесть. Единственный момент — пришлось написать код, чтобы подружить Кложу и Ring с окружением лямбды. Также поправил компиляцию Граалем, чтобы в бинарнике была верная кодировка. В будущем я планирую вынести код Яндекс.Облака в отдельную библиотеку, чтобы избавиться от копипасты.
Форма поддерживает синтаксис Markdown. Пока что нет кнопок выделения текста болдом и италиком, сделаю потом. Форма отправляется чистым POST, никаких аяксов, хотя первую версию я сделал на fetch, JSON и CORS. Про CORS я все забыл, и пришлось читать свою же статью о том, как все настроить.
Новые комментарии совмещают модерацию. После отправки создается PR в блог, мне приходит письмо, а пользователь переходит на прошлую страницу. Если все в порядке, я мерджу ветку и заливаю свежий билд блога. Таким образом, с момента публикации комментария может пройти от пяти минут до нескольких дней, но это ничего.
Первые комментарии я получил от кого? Правильно, от спамеров. Этим утром предложили виагру, казино и просто левые ссылки. Вот ссылка на уже закрытый RP и его содержимое:
---
id: 1663659055173
is_spam: false
is_deleted: false
post: /bookshelf/
date: 2022-09-20 07:30:55 +0000
author_fullname: 'epiehuliqukib'
---
http://slkjfdf.net/ - Tatacatay <a href="http://slkjfdf.net/">Aebaluk</a>
lwk.wlgg.grishaev.me.mrq.mn http://slkjfdf.net/
Очевидно, нужно вводить капчу для защиты от ботов. Я рассматриваю это как новый вызов: как сделать капчу без Javascript в статичном блоге? Уже есть мыслишки, расскажу в четвертой части эпопеи.
Наконец, последний тезис — зачем вы это делаете, мистер Андерсон? Зачем эти отказы, костыли, превозможения? Ответ — потому что могу. Просто хочется экспериментов. Надоели тормозные сайты с JS, хочу маленький оазис в своем огороде.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter
Your name, 20th Sep 2022, link
И правда работает
Mike, 20th Sep 2022, link
Testing comments
nikita, 20th Sep 2022, link
test!
Стас, 20th Sep 2022, link
Недавно кстати яндекс добавил свою капчу в список облачных сервисов, было бы интересно, если бы вы пощупали и рассказали о впечатлениях.
, 20th Sep 2022, link
Против ботов отлично работает скрытое поле с name=”email”. Чтобы в ловушку не попадали простые юзеры: 1) Следует добавить autocomplete=”off”. Я не помню, откуда я это спёр. Но кажется вероятным, что какой-нибудь глупый браузер может писать почту хозяина в поле email автоматом. 2) placeholder=”Оставьте это поле пустым”. Для тех, у кого стили не подгрузились, либо свой юзер-стиль, либо режим reader, либо консольный браузер.
Кроме того, если произошла ошибка, стоит при нажатии “Вернуться к обсуждению” предзаполнять форму отправленными данными. Терять ввод пользователя ух какой моветон.
avr, 21st Sep 2022, link
Это хорошая модернизация. Спасибо!
Ivan Grishaev, 22nd Sep 2022, link
Проверка капчи!
Александр, 25th Sep 2022, link
Изящное решение с Капчей. Вообще, изящное решение с упрощением. От бессмысленного избытка интерактива, деланого только “потому, что у всех так”, тошнит.
Никита, 3rd Oct 2022, link
а не думал вместо лямбды просто дергать github action? https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow
тут и гит из коробки, и не надо платить облакам
Ivan Grishaev, 3rd Oct 2022, link
Не совсем понял из документации, как сделать новую ветку, коммит в нее и PR.
Никита, 3rd Oct 2022, link
например, экшн
и потом можно дергать https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event прямо по http
Ivan Grishaev, 3rd Oct 2022, link
Спасибо за пример. Правда, все равно не понято, откуда приходят данные POST-формы и как их валидировать.
Ivan Grishaev, 4th Oct 2022, link
Вчитался, стало понятей. Однако неясно, как протестировать весь процесс локально. Ну и как перенаправить пользователя на нужную страницу.