От идеи до облака за вечер: Как я собрал портфолио на FastAPI и запустил его на Railway.

От идеи до облака за вечер: Как я собрал портфолио на FastAPI и запустил его на Railway.

Привет, дорогой читатель! 👋 Сегодня расскажу тебе историю о том, как я превратил пару сотен строк кода в работающее портфолио, которое теперь живёт в облаке и даже умеет отправлять письма. Звучит как магия? На самом деле, всё проще, чем кажется. Давай разберём по косточкам.

Зачем вообще FastAPI для статичного сайта? 🤔

Справедливый вопрос! Ведь для визитки обычно хватает HTML/CSS. Но я хотел три вещи:

  1. Контактную форму, которая реально работает (а не просто красивая кнопка)
  2. Автоматическую отправку писем мне и пользователю
  3. Лёгкую масштабируемость — вдруг захочу добавить API для блога?

И тут на сцену выходит FastAPI — фреймворк от Себастьяна Рамиреса, который взорвал мир Python-бэкендов в 2018 году. Его философия — скорость, простота и автоматическая документация. Представь: ты описываешь данные через Pydantic, а фреймворк сам генерирует OpenAPI-спецификацию и красивый Swagger UI. Разве это не чудо?

Аналитика: FastAPI обогнал по скорости даже Flask и Django REST Framework в тестах TechEmpower, благодаря асинхронности на Starlette и валидации через Pydantic. Крупные клиенты? Microsoft, Uber, Netflix экспериментируют с ним.

От идеи до облака за вечер: Как я собрал портфолио на FastAPI и запустил его на Railway.

Архитектура: Что под капотом?

Мой проект — это классическое MVC (Model-View-Controller), но в терминах FastAPI:

from fastapi import FastAPI from contextlib import asynccontextmanager @asynccontextmanager async def lifespan(app: FastAPI): print("App starting up...") yield print("App shutting down...") app = FastAPI(lifespan=lifespan)

Видишь этот lifespan? Это новинка FastAPI 0.104+ — менеджер контекста для управления жизненным циклом приложения. Раньше были события startup/shutdown, но теперь всё элегантнее и асинхроннее.

Шаблонизация: Jinja2 как старый друг

Хотя FastAPI часто используют для чистого API, он отлично работает с шаблонами:

from fastapi.templating import Jinja2Templates templates = Jinja2Templates(directory="templates")

В папке templates лежит index.html — обычный HTML с Bootstrap 5, но с магией Jinja2:

{% for project in projects %} <div class="col-md-4"> <h3>{{ project.title }}</h3> <p>{{ project.desc }}</p> </div> {% endfor %}

Статика (CSS, JS, картинки) монтируется одной строкой:

app.mount("/static", StaticFiles(directory="static"), name="static")

Самое интересное: контактная форма с двойной отправкой

А теперь давай разберём самую сочную часть — форму обратной связи. Я хотел, чтобы:

  1. Мне приходило уведомление о новом сообщении
  2. Отправитель получал автоответ
  3. Всё работало асинхронно, чтобы пользователь не ждал

Pydantic v2: Валидация как искусство

Сначала определяем модель данных:

from pydantic import BaseModel, EmailStr from pydantic.v1 import ValidationError # Обратная совместимость class ContactMessage(BaseModel): name: str email: EmailStr # Автоматическая валидация email! message: str @property def summary(self) -> str: return f"Message from {self.name}: {self.message[:50]}..."

Pydantic v2, выпущенный в 2023, стал на 5-50x быстрее благодаря Rust-компонентам. Проверка EmailStr использует регулярные выражения RFC 5322 — никаких фейковых email'ов!

SMTP: Старый-добрый протокол в новом свете

Для отправки почты я использовал стандартную библиотеку smtplib с STARTTLS (порт 587):

async def send_notification_email(msg: ContactMessage): with smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=30) as server: server.starttls() # Шифруем соединение server.login(SMTP_USERNAME, SMTP_PASSWORD) server.sendmail(SMTP_USERNAME, RECIPIENT_EMAIL, message.as_string())

Важный момент: для Gmail нужно использовать App Password, а не обычный пароль. Это OAuth2-упрощённая схема, которую Google ввел в 2022 для повышения безопасности.

BackgroundTasks: Магия асинхронности

Вот где FastAPI показывает свою элегантность:

@app.post("/contact") async def contact( name: str = Form(...), email: str = Form(...), message: str = Form(...), background_tasks: BackgroundTasks = BackgroundTasks() # Инъекция зависимостей! ): msg = ContactMessage(name=name, email=email, message=message) # Две независимые задачи в фоне background_tasks.add_task(send_notification_email, msg) # Мне background_tasks.add_task(send_auto_reply, msg) # Пользователю return {"status": "success", "message": "Сообщение отправлено!"}

Пользователь мгновенно получает ответ, а письма отправляются в фоне. Если что-то пойдёт не так с email — форма всё равно отработает успешно! BackgroundTasks использует тот же event loop, что и основное приложение, но без блокировки.

Логирование: Что происходит внутри?

Я добавил детальное логирование, чтобы видеть каждый шаг:

import logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) # В коде отправки: logger.info(f"🔗 Подключаемся к {SMTP_SERVER}:{SMTP_PORT}") logger.error(f"❌ Ошибка авторизации SMTP: {e}")

В продакшене можно настроить JSON-логи для Elasticsearch или Sentry, но для стартапа хватает и такого.

Деплой на Railway: От локальной машины к облаку за 5 минут

Railway — это Platform-as-a-Service от бывших инженеров AWS и Google, запущенный в 2020. Их философия: "деплой должен быть простым как git push".

Шаг 1: Подготовка зависимостей

requirements.txt — минималистичный:

fastapi==0.104.1 uvicorn[standard]==0.24.0 python-dotenv==1.0.0 jinja2==3.1.2

Procfile для Railway:

web: uvicorn main:app --host=0.0.0.0 --port=${PORT:-8000}

Шаг 2: Переменные окружения — секреты в безопасности

Никаких паролей в коде! Railway имеет встроенный Vault-like storage для секретов:

from dotenv import load_dotenv import os load_dotenv() SMTP_PASSWORD = os.getenv("SMTP_PASSWORD") # Безопасно!

В панели Railway добавляем переменные:

  • SMTP_SERVER=smtp.gmail.com
  • SMTP_PORT=587
  • SMTP_USERNAME=ваш@gmail.com
  • SMTP_PASSWORD=пароль-приложения ← вот это критично!
  • RECIPIENT_EMAIL=куда_отправлять@gmail.com

Шаг 3: Git push и магия начинается

git add . git commit -m "Готово к деплою" git push railway main

Railway автоматически:

  1. Определяет Python-проект
  2. Устанавливает зависимости через pip
  3. Запускает uvicorn с правильными параметрами
  4. Выдаёт HTTPS-домен с Let's Encrypt сертификатом

А теперь самое интересное: Railway использует Nixpacks — открытый инструмент для сборки образов. Это как Dockerfile, но умнее. Он сам определяет, что у тебя Python-проект и как его собрать.

От идеи до облака за вечер: Как я собрал портфолио на FastAPI и запустил его на Railway.

Проблемы и их решения 🛠

Проблема 1: SMTP не работает в продакшене

Решение: Вместо прямого SMTP к Gmail можно использовать SendGrid или Mailgun (у них есть бесплатные тарифы). Их API надёжнее и не блокируются провайдерами.

Проблема 2: Статика не обновляется

Решение: Я добавил хэши в имена CSS-файлов или можно использовать CDN. Но для простого портфолио хватает и встроенной раздачи.

Проблема 3: Нужна база данных для хранения сообщений

Решение: Railway предлагает PostgreSQL в один клик. В FastAPI достаточно добавить:

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine DATABASE_URL = os.getenv("DATABASE_URL").replace("postgres://", "postgresql+asyncpg://") engine = create_async_engine(DATABASE_URL)

Что можно улучшить?

  1. HTTPS редирект — FastAPI легко настраивается через middleware
  2. Rate limiting — чтобы спамеры не завалили форму
  3. Telegram-уведомления — кроме email, слать сообщение в Telegram бот
  4. Кэширование через Redis (есть на Railway за $7/мес)
От идеи до облака за вечер: Как я собрал портфолио на FastAPI и запустил его на Railway.

Итог: что получилось?

За один вечер я собрал:

  • Сайт-портфолио с адаптивным дизайном
  • Рабочую контактную форму с двойной отправкой
  • Автоматический деплой с HTTPS
  • Мониторинг через Railway Dashboard

Общая стоимость? $0 на стартовом тарифе Railway. Бесплатно дают $5 кредитов, которых хватит на несколько месяцев работы.

FastAPI доказал, что он идеален не только для микросервисов, но и для маленьких проектов. Асинхронность, автоматическая документация и скорость разработки — это тот самый sweet spot.

Документация для углубления:

🙌 Ну что, вдохновился?Если статья была полезной и ты тоже хочешь собрать своё портфолио на FastAPI — ставь лайк! Подписывайся, дальше разберём, как добавить к этому блог с комментариями и подпиской на рассылку.

Пиши в комментариях, с какими сложностями столкнулся при деплое своих проектов? Используешь Railway, Heroku или свой сервер? Давай обсудим!

Начать дискуссию