Перейти к содержимому
N1
Интеграции · 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