Notion API и картинки

Я тут хвастался переводом блога на Notion API. Все хорошо работает, кроме отображения картинок, но тут надо дать контекста.

При разработке блогов нормальные кенты используют статическую генерацию страниц, чтобы моментально грузить контент. Современные NextJS и Gatsby как раз на этом преимуществе и запускались.

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

Теперь про Notion. Когда ты загружаешь туда картинку, он сохраняет ее в Amazon S3. Если в Notion API запросить ссылку на эту картинку, то он отдаст подписанную ссылку, которая действительна только один час. Если перейти по ней позже, то будет 403 ошибка.

Через час картинка превращается в 403 ошибкуЧерез час картинка превращается в 403 ошибку

А теперь скрещиваем и получаем проблему: ты написал статей на Notion, собрал сайт на NextJS и выкатил его на пользователей. В итоге у тебя страницы с картинками, которые валидны один час. Сначала пользователи радуются, а потом читают текст без картинок — не круто.

Что сразу приходит в голову, когда задумываешься о починке:

  1. Уйти со статической генерации страниц и быть как все. Отбрасываем такой вариант сразу, потому что теряем в скорости загрузки страниц и зачем тогда вот это все.
  2. Уйти с Amazon S3 на какой-нибудь Cloudinary или Firebase, где есть вечные ссылки. Если можно сделать это автоматически, чтобы Notion сразу туда грузил изображения, то это вариант, почему нет. Возможно, так можно сделать через сторонние интеграции, но я не проверял.
  3. При сборке сайта выкачивать изображения в статическую папку на сервере и раздавать оттуда. В целом, это ок вариант, если изображений немного. Это точно более выигрышный вариант по производительности, потому что не надо тратить время на сетевой запрос. Но этот вариант плохо масштабируемый, потому что рано или поздно упрешься в размеры диска.
  4. Один умный вариант из интернетов, который я в итоге и сделал.

Внимание, умный вариант

Jake Teton‑Landis предлагает сделать метод свой метод АПИ, где будет запрашиваться свежее изображение, кэшироваться на сервере и возвращаться пользователю. И все запросы за картинками подменить на этот метод АПИ.

По шагам:

  1. При сборке сайта находим все изображения в блоге и подменяем ссылки с S3 на свой кастомный путь, типа не https://s3.amazon.com/my_image, а https://myblog.ru/assests/{block_id}
  2. Создаем этот кастомный роут /assests/{block_id}. Логика такая: роут получает айди блока в ноушене, делает запрос за блоком в ноушн, где есть ссылка на изображение, потом делает запрос за изображением, кэширует его у себя заголовком Cache-Control и отдает клиенту.

NextJS позволяет создавать кастомные роуты, так что время уходит только на написание кода.

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

Если интересует код — велком на гитхаб.