Интеграции · Go · REST API
REST API интернет-магазина на Go: заказы без дублей и остатки без ухода в минус
Клиент:
Личный проект
Категория: Интеграции
Стек: Go 1.25, chi, PostgreSQL 16, pgx, sqlc, golang-migrate, JWT, bcrypt, zap, Docker Compose, GitHub Actions, golangci-lint
Срок: личный проект, 2025
Проблема
Нужен был API магазина, который корректно переживает типичные ситуации боевого трафика: повторную отправку заказа при обрыве связи и одновременную покупку последних единиц товара.
Ограничения
Повтор запроса не должен создавать второй заказ, остаток не должен уходить в минус при конкурентных заказах, а суммы — считаться без ошибок округления float.
Что сделал
- JWT-аутентификация: access-токен на 15 минут и refresh-токен, который хранится в базе только в виде хеша; роли user и admin, пароли — bcrypt
- Идемпотентность заказов по заголовку Idempotency-Key: повторный запрос возвращает сохранённый ответ, ключи живут 24 часа
- Атомарное списание остатков в транзакции: условный UPDATE не даёт уйти в минус, отмена заказа возвращает товар на склад
- Слой данных на sqlc и миграциях golang-migrate, суммы — в decimal, а не во float
- Пагинация, фильтрация и сортировка каталога, валидация входных данных, rate limit по IP, graceful shutdown, структурные логи zap
- OpenAPI 3.0 (10 путей) и Postman-коллекция; CI: сборка, миграции, 20 модульных тестов с -race и golangci-lint
Архитектура
chi-роутер + middleware
→ Сервисный слой
→ sqlc-репозитории
→ PostgreSQL 16 (транзакции)
→ OpenAPI / Postman
Результат
API закрывает цикл «регистрация → каталог → заказ → оплата или отмена» и предсказуемо ведёт себя при повторах и конкурентных заказах; каждое изменение проверяется в CI.
Что можно переиспользовать
Идемпотентность POST-запросов по Idempotency-Key
Атомарное списание остатков условным UPDATE в транзакции
Каркас Go-сервиса: chi, sqlc, zap, CI с golangci-lint