Skip to content

Repository files navigation

GoLearn — CRUD REST API

Учебный REST-сервис для управления пользователями на Go + PostgreSQL.

Возможности

Метод Путь Описание
GET /health Проверка сервиса и подключения к БД
POST /api/v1/users Создать пользователя
GET /api/v1/users Список пользователей (пагинация)
GET /api/v1/users/{id} Получить пользователя по ID
PUT / PATCH /api/v1/users/{id} Обновить пользователя
DELETE /api/v1/users/{id} Удалить пользователя

Модель User: id (UUID), name, email (уникальный), created_at, updated_at.

Требования

  • Go 1.22+
  • Docker Desktop (для PostgreSQL в dev и интеграционных тестов)

Быстрый старт

1. Запустить PostgreSQL

docker compose up -d

Контейнер поднимает Postgres 16 на порту 5432 с базой golearn.

2. Применить миграции

make migrate-up

Или вручную:

export DATABASE_URL="postgres://postgres:postgres@localhost:5432/golearn?sslmode=disable"
go run ./cmd/migrate up

3. Запустить API

export DATABASE_URL="postgres://postgres:postgres@localhost:5432/golearn?sslmode=disable"
make run

Сервер слушает http://localhost:8080.

Переменные окружения

Переменная Обязательная По умолчанию Описание
DATABASE_URL да DSN PostgreSQL
HTTP_PORT нет 8080 Порт HTTP-сервера
LOG_LEVEL нет info Уровень логов: debug, info, warn, error
LOG_FORMAT нет text Формат логов: text или json

Пример для production-подобного окружения:

export DATABASE_URL="postgres://postgres:postgres@localhost:5432/golearn?sslmode=disable"
export LOG_LEVEL=debug
export LOG_FORMAT=json
make run

Makefile

make run              # запуск API
make migrate-up       # применить миграции
make migrate-down     # откатить последнюю миграцию
make migrate-version  # текущая версия схемы

Примеры curl

Базовый URL:

BASE=http://localhost:8080

Health check

curl -s "$BASE/health" | jq

Ответ при успехе:

{"status":"ok","database":"ok"}

Создать пользователя

curl -s -X POST "$BASE/api/v1/users" \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","email":"alice@example.com"}' | jq

Ответ 201 Created:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Alice",
  "email": "alice@example.com",
  "created_at": "2026-07-07T10:00:00Z",
  "updated_at": "2026-07-07T10:00:00Z"
}

Сохраните id для следующих запросов:

USER_ID="<uuid из ответа>"

Список пользователей

curl -s "$BASE/api/v1/users?limit=20&offset=0" | jq

Параметры пагинации:

  • limit — количество записей (по умолчанию 20, максимум 100)
  • offset — смещение (по умолчанию 0)

Получить пользователя по ID

curl -s "$BASE/api/v1/users/$USER_ID" | jq

Обновить пользователя

curl -s -X PUT "$BASE/api/v1/users/$USER_ID" \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice Updated","email":"alice.updated@example.com"}' | jq

PATCH работает так же, как PUT.

Удалить пользователя

curl -s -o /dev/null -w "%{http_code}\n" -X DELETE "$BASE/api/v1/users/$USER_ID"

Ожидаемый ответ: 204 No Content.

Коды ответов

Код Когда
200 Успешное чтение или обновление
201 Пользователь создан
204 Пользователь удалён
400 Невалидный JSON, email или параметры
404 Пользователь не найден
409 Email уже занят
500 Внутренняя ошибка сервера (включая необработанную panic)
503 БД недоступна (/health)

Тело ошибки:

{"error":"user not found"}

Логирование (slog)

Сервис использует структурированное логирование через log/slog:

  • Старт/остановка — события жизненного цикла сервера
  • HTTP-запросыhttpmiddleware логирует каждый запрос: request_id, method, path, status, duration, bytes
  • Ошибки 500 — handler пишет slog.Error с контекстом запроса
  • Panic — recover-middleware логирует stack trace и отдаёт 500 с JSON {"error":"internal server error"}

Логгер собирается в main через logging.New(LOG_LEVEL, LOG_FORMAT); пакет config содержит только данные из env.

Пример лога (формат text):

level=INFO msg="request completed" request_id=abc-123 method=POST path=/api/v1/users status=201 bytes=156 duration=12.5ms remote_addr=127.0.0.1:54321

Для агрегации в ELK/Loki используйте LOG_FORMAT=json.

Таймауты HTTP-сервера

Защита от «зависших» клиентов и Slowloris-атак:

Таймаут Значение Назначение
ReadHeaderTimeout 5s Ожидание заголовков запроса
ReadTimeout 5s Чтение тела запроса
WriteTimeout 15s Запись ответа клиенту
IdleTimeout 60s Keep-alive без активности
Handler timeout 10s Middleware: максимальное время обработки запроса
Shutdown timeout 10s Graceful shutdown по SIGINT/SIGTERM

Тесты

go test -race -count=1 ./...

Интеграционные тесты используют testcontainers (Docker должен быть запущен).

Структура проекта

cmd/api/              — точка входа
cmd/migrate/          — CLI для миграций (up/down/version)
internal/
  config/             — конфигурация из env
  logging/            — сборка slog-логгера
  domain/             — модель User, доменные ошибки
  service/            — бизнес-логика
  handler/            — HTTP handlers
  httperr/            — единый JSON-формат ошибок
  httpmiddleware/     — slog logging, recover
  repository/postgres/— SQL-репозиторий
  database/           — pgx pool, миграции
  mocks/              — testify-моки для unit-тестов
  testdb/             — testcontainers для postgres-тестов
migrations/           — SQL-миграции (формат tern, встраиваются через go:embed)
tern.conf             — конфиг tern CLI
test/integration/     — интеграционные тесты

Архитектура

HTTP Client → chi + httpmiddleware → Handler → Service → Repository → PostgreSQL

Зависимости направлены внутрь: handler знает service, service знает интерфейс репозитория, postgres реализует интерфейс.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages