Минимализм: Когда фреймворки — это перебор.

Сегодня под любую задачу найдётся фреймворк: для сайтов — Django, для API — FastAPI, для ботов — aiogram. Но что, если задача элементарна? Например, нужно просто, чтобы при обращении к определённому адресу в браузере на сервере запускался Python-скрипт. Без базы данных, без роутинга, без десятков зависимостей. В этом случае фреймворки — как молоток для открывания бутылки: можно, но громоздко. Нам подойдёт чистый, прямолинейный подход — минимальный Python и чуть-чуть системной магии.

aiohttp — лёгкий путь в мир API без лишнего веса

Для эксперимента я решил собрать простой тестовый пример — без лишнего шума, просто чтобы понять, как это всё работает. И тут снова выручила моя старая знакомая — библиотека aiohttp. Она, кроме того что асинхронная, так еще и универсальная: может быть и клиентом, и сервером. При этом весит очень мало и почти не грузит систему. В отличие от тяжеловесных фреймворков, aiohttp — это швейцарский нож для Python-разработчика (у меня есть статья с таким названием 🙂 ), которому нужно быстро и аккуратно решить задачу.

Аскетичная лаборатория: VPS + Apache + Python = API

Итак, поле для экспериментов готово: недорогой VPS с Ubuntu, установленный Apache и доменное имя, направленное на этот сервер. Минимум технологий — максимум пользы. Это идеальная песочница, чтобы не просто читать про API, а действительно понять, как он работает. Цель проста: создать эндпоинт http://site.com/hi, который по запросу будет радостно отвечать браузеру строкой:

«Привет! Это твой первый API!»

Вот и весь план — без фреймворков, без баз данных, без Docker и прочей артиллерии. Только Python, aiohttp и Apache, объединённые в простую, но работающую систему.

Простой aiohttp-сервер шаг за шагом

Первым делом я написал вот такое, по сути минимальный пример из официальной документации к aiohttp:

from aiohttp import web

async def hi_handler(request):
    return web.Response(text='Привет! Это твой первый API!', content_type='text/plain')

app = web.Application()
app.router.add_get('/hi', hi_handler)

if __name__ == '__main__':
    web.run_app(app, host='127.0.0.1', port=8080)

Несмотря на то, что код получился небольшой, это вполне рабочий web сервер. Спасибо aiohttp!

Разбор кода сервера

Давайте разберёмся, что именно делает этот код. Он создает простой HTTP-сервер с помощью библиотеки aiohttp, который отвечает на запрос по адресу /hi. Вот пошаговое объяснение:

from aiohttp import web

Импортируем модуль web из библиотеки aiohttp. Это основа для создания серверной части: здесь есть всё — от приложения до маршрутизаторов и ответа.

async def hi_handler(request):
    return web.Response(text='Привет! Это твой первый API!', content_type='text/plain')

Мы создаём асинхронную функцию-обработчик, которая будет вызываться при обращении к определённому URL (в данном случае — /hi).

  • async def — функция объявлена как асинхронная. Это позволяет серверу обрабатывать сразу несколько запросов, не блокируя выполнение.
  • web.Response(…) — отправляем клиенту ответ:
    • text=’Привет!...’ — текст, который увидит пользователь.
    • content_type=‘text/plain’ — тип содержимого, обычный текст.
app = web.Application()

Создаём экземпляр веб-приложения. Это как пустая коробка, в которую мы будем складывать маршруты, настройки и другие элементы сервера.

app.router.add_get('/hi', hi_handler)

Регистрируем маршрут:

  • При GET-запросе к адресу /hi вызывается функция hi_handler.
  • Это и есть та самая “дверь”, через которую пользователь попадает в нашу функцию.
if __name__ == '__main__':
    web.run_app(app, host='127.0.0.1', port=8080)

Запускаем сервер:

  • web.run_app(app, …) — стартует веб-сервер и начинает слушать указанный адрес и порт.
  • host=‘127.0.0.1’ — сервер доступен только с этого компьютера (локально).
  • port=8080 — порт, на котором всё будет работать. Можно открыть браузер и набрать http://127.0.0.1:8080/hi, чтобы увидеть результат.

if __name__ == ‘__main__’: — стандартная проверка, чтобы код запускался только если файл был запущен напрямую, а не импортирован как модуль.

И вот, за несколько строк мы получаем рабочий HTTP-сервер, который обрабатывает запросы асинхронно и отвечает браузеру строкой. Всё просто.

Подключаем Apache как обратный прокси

Теперь, когда у нас есть работающий скрипт на aiohttp, надо сделать так, чтобы его можно было вызывать не только по localhost, а снаружи — через браузер по обычному HTTP-запросу. В этом нам поможет Apache, выступая в роли обратного прокси (reverse proxy).

Что такое обратный прокси?

Это когда Apache принимает внешний запрос (например, на http://yourdomain.ru/hi), а сам прокидывает его внутрь — на наш Python-сервер, работающий на 127.0.0.1:8080. Пользователь этого даже не заметит: для него всё выглядит, как обычный сайт.

Что нужно сделать

Откроем конфигурационный файл сайта в Apache. Это может быть, например:

/etc/apache2/sites-available/000-default.conf

или, если у нас виртуальный хост (у меня есть сайты на сервере, у меня так):

/etc/apache2/sites-available/site.com.conf

Добавляем внутрь блока вот это:

ProxyPreserveHost On
ProxyPass '/hi' 'http://127.0.0.1:8080/hi'
ProxyPassReverse '/hi' 'http://127.0.0.1:8080/hi'

Что делают эти строки:

  • ProxyPreserveHost On — сохраняет оригинальный заголовок Host, передаваемый клиентом.
  • ProxyPass — говорит Apache, что все обращения к /hi надо прокидывать на Python-сервер.
  • ProxyPassReverse — корректно возвращает ответы от Python обратно пользователю.

Не забудем включить нужные модули Apache через терминал Ubuntu, или что там у нас на VPS:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2

Результат

Теперь, когда ты откроешь в браузере:

http://site.com/hi

Apache примет этот запрос и передаст его Python-серверу, а ответ — вернёт обратно. Всё работает как одно целое, и никто не догадывается, что под капотом — aiohttp.

Гибкая и лёгкая основа для собственного API

Теперь у тебя есть минималистичная, но мощная связка:

aiohttp — лёгкий Python-сервер, быстро реагирующий на запросы. Apache — фронтенд, работающий как прокси, принимающий HTTP/HTTPS-запросы.

Эта пара уже даёт отличную базу для чего угодно:

легко прикручивается HTTPS через Let’s Encrypt или другой сертификат; можно оформить запуск Python-сервера как systemd-сервис, чтобы он стартовал вместе с системой; удобно добавлять новые эндпоинты под конкретные задачи: от запуска скриптов до интеграций с другими сервисами; и всё это без тяжеловесных фреймворков и лишнего кода.

Такой подход особенно хорош, когда нужен небольшой серверный функционал, а не огромная платформа — быстро, просто и под полным контролем.

Зачем всё это: мониторинг без лишнего шума

Этот мини-сервер я сделал не просто так. Мне нужно было удобно следить за состоянием моего VPS, где совсем немного оперативки. Идея простая: открываю страницу в браузере → получаю свободную память и список топ ресурсоёмких процессов.

Никаких входов по SSH, никаких тяжёлых дашбордов. Просто быстрый запрос и понятный ответ — всё, что нужно для рутинной проверки в моменте.

Есть конечно еще мобильный терминал для смартфона, но с его экрана не очень удобно писать команды по SSH.

Добавить эту логику в скрипт с aiohttp — дело пары строк. Вместо “Привет” он может возвращать, например:

  • количество свободной оперативной памяти,
  • список самых «тяжёлых» процессов (CPU / RAM),
  • аптайм сервера,
  • место на диске и тп.

Насколько «лёгкий» aiohttp на деле?

Я специально посмотрел: сам импорт aiohttp в интерпретатор Python на моём VPS увеличивает потребление памяти примерно на 10 МБ ОЗУ. Это, конечно, не ноль, но вполне разумная цена за:

  • сервер на Python, который держит соединение;
  • асинхронную обработку запросов;
  • лёгкость в доработке под любые задачи.

В общем, если нужен свой маленький API, без тяжёлых фреймворков — aiohttp + Apache как прокси дают отличную основу. Всё просто, прозрачно и гибко.

Фото аватара

От exrf

Добавить комментарий