Production-ready REST API с Clean Architecture, PostgreSQL и полной документацией
Полноценное приложение для управления пользователями, демонстрирующее best practices разработки на Go:
- ✅ Clean Architecture (3 слоя)
- ✅ PostgreSQL база данных
- ✅ REST API с CRUD операциями
- ✅ Dependency Injection
- ✅ Интерфейсы для тестируемости
- ✅ Миграции БД
┌─────────────────────────────────────┐
│  HTTP Handler (presentation)        │  ← Принимает HTTP запросы
│  /internal/handler/                 │
└────────────┬────────────────────────┘
             ↓
┌─────────────────────────────────────┐
│  Service (business logic)           │  ← Валидация и бизнес-логика
│  /internal/service/                 │
└────────────┬────────────────────────┘
             ↓
┌─────────────────────────────────────┐
│  Repository (data access)           │  ← SQL запросы
│  /internal/repository/              │
└────────────┬────────────────────────┘
             ↓
┌─────────────────────────────────────┐
│  PostgreSQL Database                │  ← Хранение данных
└─────────────────────────────────────┘
- Разделение ответственности - каждый слой делает своё
- Dependency Injection - зависимости внедряются через конструкторы
- Интерфейсы - слои общаются через контракты
- Тестируемость - легко заменить любой слой моками
user_management_api/
├── main.go                           # Точка входа приложения
├── go.mod                            # Зависимости
├── go.sum                            # Хеши зависимостей
├── env.example                       # Пример конфигурации
│
├── migrations/                       # SQL миграции
│   └── 001_create_users.sql         # Создание таблицы users
│
└── internal/                         # Внутренние пакеты (не экспортируются)
    │
    ├── config/                       # Конфигурация
    │   └── config.go                # Загрузка настроек из ENV
    │
    ├── domain/                       # Модели данных (Domain Layer)
    │   └── user.go                  # Структуры User, CreateUserRequest, etc.
    │
    ├── repository/                   # Слой работы с БД (Data Layer)
    │   └── user_repository.go       # SQL запросы (CRUD)
    │
    ├── service/                      # Бизнес-логика (Business Layer)
    │   └── user_service.go          # Валидация, обработка данных
    │
    └── handler/                      # HTTP обработчики (Presentation Layer)
        └── user_handler.go          # REST API endpoints
- Go 1.21+
- Docker (для PostgreSQL)
- curl (для тестирования)
git clone <your-repo-url>
cd 07_modular_app# Запуск через Docker
docker run --name postgres \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  -d postgres
# Создание базы данных
docker exec -it postgres psql -U postgres -c "CREATE DATABASE user_management;"
# Применение миграций
docker exec -i postgres psql -U postgres -d user_management < migrations/001_create_users.sql# Скопируйте пример конфигурации
cp env.example .env
# Отредактируйте .env если нужно (опционально)go mod tidygo run main.goСервер запустится на http://localhost:8080
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice@example.com",
    "name": "Alice",
    "password": "secret123"
  }'Ответ:
{
  "id": 1,
  "email": "alice@example.com",
  "name": "Alice",
  "created_at": "2025-10-15T10:00:00Z",
  "updated_at": "2025-10-15T10:00:00Z"
}curl http://localhost:8080/usersОтвет:
[
  {
    "id": 1,
    "email": "alice@example.com",
    "name": "Alice",
    "created_at": "2025-10-15T10:00:00Z",
    "updated_at": "2025-10-15T10:00:00Z"
  }
]curl http://localhost:8080/users/1curl -X PUT http://localhost:8080/users/1 \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice.updated@example.com",
    "name": "Alice Updated"
  }'curl -X DELETE http://localhost:8080/users/1Ответ:
{
  "message": "User deleted"
}Приложение настраивается через environment variables:
| Переменная | Описание | По умолчанию | 
|---|---|---|
| DB_HOST | Хост PostgreSQL | localhost | 
| DB_PORT | Порт PostgreSQL | 5432 | 
| DB_USER | Пользователь БД | postgres | 
| DB_PASSWORD | Пароль БД | postgres | 
| DB_NAME | Имя базы данных | user_management | 
| SERVER_PORT | Порт HTTP сервера | 8080 | 
# Запуск на другом порту
SERVER_PORT=3000 go run main.go
# С другими настройками БД
DB_HOST=db.example.com DB_PORT=5433 go run main.go| Колонка | Тип | Описание | 
|---|---|---|
| id | SERIAL PRIMARY KEY | Уникальный идентификатор | 
| email | VARCHAR(255) UNIQUE | Email (уникальный) | 
| name | VARCHAR(255) | Имя пользователя | 
| password | VARCHAR(255) | Пароль (в production хешируется) | 
| created_at | TIMESTAMP | Время создания | 
| updated_at | TIMESTAMP | Время последнего обновления | 
Индексы:
- PRIMARY KEY на id
- UNIQUE INDEX на email
- INDEX на emailдля быстрого поиска
# 1. Создать пользователя
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","name":"Test User","password":"password123"}'
# 2. Получить всех пользователей
curl http://localhost:8080/users
# 3. Получить конкретного пользователя
curl http://localhost:8080/users/1
# 4. Обновить пользователя
curl -X PUT http://localhost:8080/users/1 \
  -H "Content-Type: application/json" \
  -d '{"email":"updated@example.com","name":"Updated Name"}'
# 5. Удалить пользователя
curl -X DELETE http://localhost:8080/users/1
# 6. Проверить удаление
curl http://localhost:8080/users# Создание с невалидными данными
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{"email":"","name":"","password":"12"}' # Короткий пароль
# Получение несуществующего пользователя
curl http://localhost:8080/users/9999
# Невалидный ID
curl http://localhost:8080/users/abc- Go 1.21 - язык программирования
- PostgreSQL - реляционная БД
- net/http - стандартная библиотека для HTTP
- database/sql - стандартная библиотека для работы с БД
- lib/pq - PostgreSQL драйвер
- Clean Architecture - разделение на слои
- Repository Pattern - абстракция работы с данными
- Dependency Injection - внедрение зависимостей
- Interface Segregation - маленькие интерфейсы
// internal/domain/user.go
type User struct {
    ID        int       `json:"id"`
    Email     string    `json:"email"`
    Name      string    `json:"name"`
    Password  string    `json:"-"` // Не показываем в JSON!
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}// internal/repository/user_repository.go
type UserRepository interface {
    Create(req *domain.CreateUserRequest) (*domain.User, error)
    GetByID(id int) (*domain.User, error)
    GetAll() ([]domain.User, error)
    Update(id int, req *domain.UpdateUserRequest) (*domain.User, error)
    Delete(id int) error
}// internal/service/user_service.go
type UserService interface {
    CreateUser(req *domain.CreateUserRequest) (*domain.User, error)
    GetUser(id int) (*domain.User, error)
    GetAllUsers() ([]domain.User, error)
    UpdateUser(id int, req *domain.UpdateUserRequest) (*domain.User, error)
    DeleteUser(id int) error
}// internal/handler/user_handler.go
type UserHandler struct {
    service service.UserService
}
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request)
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request, id int)
// ... другие методы// main.go
userRepo := repository.NewUserRepository(db)
userService := service.NewUserService(userRepo)  // Внедряем repo
userHandler := handler.NewUserHandler(userService) // Внедряем service// Легко заменить на mock для тестов
type UserRepository interface {
    Create(...) error
    GetByID(...) (*User, error)
}func (s *userService) CreateUser(req *domain.CreateUserRequest) (*domain.User, error) {
    if req.Email == "" {
        return nil, errors.New("email обязателен")
    }
    if len(req.Password) < 6 {
        return nil, errors.New("пароль должен быть минимум 6 символов")
    }
    // ...
}query := `SELECT * FROM users WHERE id = $1` // $1 - безопасный параметр
db.QueryRow(query, id).Scan(...)# Найти процесс на порту 8080
lsof -i :8080
# Убить процесс
kill -9 <PID>
# Или использовать другой порт
SERVER_PORT=3000 go run main.go# Проверить, запущен ли контейнер
docker ps | grep postgres
# Если не запущен - запустить
docker start postgres
# Проверить логи
docker logs postgres# Создать БД
docker exec -it postgres psql -U postgres -c "CREATE DATABASE user_management;"
# Применить миграции
docker exec -i postgres psql -U postgres -d user_management < migrations/001_create_users.sqlЭтот проект содержит подробные комментарии в каждом файле, объясняющие:
- Как работает каждая строка кода
- Почему используется именно этот подход
- Какие альтернативы существуют
- internal/domain/user.go- начните с моделей данных
- internal/repository/user_repository.go- SQL запросы и работа с БД
- internal/service/user_service.go- бизнес-логика и валидация
- internal/handler/user_handler.go- HTTP обработчики
- main.go- сборка всего вместе (Dependency Injection)
- ✅ Структуры и методы
- ✅ Интерфейсы и их реализация
- ✅ Указатели (value vs pointer receiver)
- ✅ Error handling
- ✅ Пакеты и модули
- ✅ Clean Architecture
- ✅ Repository Pattern
- ✅ Dependency Injection
- ✅ Interface Segregation
- ✅ Подключение к PostgreSQL
- ✅ SQL миграции
- ✅ CRUD операции
- ✅ Параметризованные запросы
- ✅ QueryRow vs Query vs Exec
- ✅ REST API design
- ✅ HTTP методы (GET, POST, PUT, DELETE)
- ✅ Статус коды (200, 201, 400, 404, 500)
- ✅ JSON encoding/decoding
- ✅ Routing
- Хешируйте пароли с помощью bcrypt:
import "golang.org/x/crypto/bcrypt"
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)- 
Используйте HTTPS вместо HTTP 
- 
Добавьте аутентификацию (JWT tokens) 
- 
Добавьте rate limiting для защиты от атак 
- 
Валидируйте email с помощью regex или библиотек 
- 
Аутентификация - JWT tokens
- Login/Logout endpoints
- Middleware для проверки токенов
 
- 
Логирование - Structured logging (zap, zerolog)
- Request logging middleware
- Error logging
 
- 
Тестирование - Unit тесты
- Integration тесты
- Моки для repository
 
- 
Middleware - CORS
- Rate limiting
- Recovery from panic
 
- 
Роутер - chi, gorilla/mux, или gin
- Более удобная работа с параметрами
 
- 
Валидация - validator библиотека
- Custom validation rules
 
- 
Миграции - golang-migrate
- Автоматическое применение при старте
 
- 
Docker - Dockerfile для приложения
- docker-compose.yml для всего стека
 
| Код | Название | Когда используется | 
|---|---|---|
| 200 | OK | Успешный GET/PUT | 
| 201 | Created | Успешный POST | 
| 400 | Bad Request | Невалидные данные | 
| 404 | Not Found | Ресурс не найден | 
| 405 | Method Not Allowed | Неподдерживаемый HTTP метод | 
| 500 | Internal Server Error | Ошибка сервера/БД | 
if err != nil {
    return nil, err
}defer db.Close()
defer rows.Close()
defer r.Body.Close()// ✅ Правильно (безопасно)
query := `SELECT * FROM users WHERE id = $1`
db.QueryRow(query, id)
// ❌ Неправильно (SQL injection!)
query := fmt.Sprintf("SELECT * FROM users WHERE id = %d", id)type User struct {
    ID       int    `json:"id"`
    Password string `json:"-"`  // Не показывать в JSON!
}// Определяем интерфейс там, где используем (service),
// а не там, где реализуем (repository)- Effective Go - официальное руководство
- PostgreSQL документация
- Clean Architecture
- Go database/sql tutorial
Создано как учебный проект для изучения Go и Clean Architecture.
MIT License - используйте свободно для обучения и разработки.
Этот проект демонстрирует понимание:
- ✅ Go синтаксиса и идиом
- ✅ Clean Architecture
- ✅ REST API design
- ✅ Работы с PostgreSQL
- ✅ Error handling
- ✅ Dependency Injection
- ✅ Интерфейсов и их применения