← Назад к вопросам

Где находится описание поддерживаемых API в чистой архитектуре?

2.0 Middle🔥 241 комментариев
#Микросервисы и архитектура#Сетевые протоколы и API

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Описание поддерживаемых API в чистой архитектуре

В чистой архитектуре (Clean Architecture), популяризованной Робертом Мартином, описание поддерживаемых API находится на внешнем слое (фреймворков и драйверов) или, более конкретно, в так называемом слое интерфейсов (interface adapters). Этот слой отвечает за преобразование данных между удобными для бизнес-правил форматами и удобными для внешних агентов (таких как веб, базы данных, UI) форматами.

Конкретное расположение и компоненты

В типичной реализации чистой архитектуры на Go, API описывается в следующих ключевых местах:

1. Transport Layer (Слой транспорта)

Это точка входа внешних запросов (HTTP, gRPC, CLI и т.д.). Здесь находятся:

  • Маршрутизаторы (роутеры) — например, с использованием gorilla/mux, chi или стандартного http.ServeMux.
  • Обработчики (handlers) или контроллеры (controllers) — которые принимают HTTP-запросы, преобразуют их в вызовы Use Case (сценариев использования).

Пример структуры папок:

├── cmd/
│   └── api/
│       └── main.go          # точка входа
├── internal/
│   ├── transport/
│   │   └── http/
│   │       ├── handlers/    # обработчики HTTP
│   │       │   └── user_handler.go
│   │       └── router.go    # описание маршрутов
│   ├── usecase/             # сценарии использования
│   └── entity/              # бизнес-сущности

2. Файлы описания маршрутов (Router Definitions)

В Go обычно создается отдельный файл, где явно описываются все поддерживаемые эндпоинты:

// internal/transport/http/router.go
package http

import (
    "github.com/gorilla/mux"
    "myapp/internal/usecase"
)

func NewRouter(userUseCase usecase.UserUseCase) *mux.Router {
    r := mux.NewRouter()
    
    // Описание API
    r.HandleFunc("/api/v1/users", GetUsers(userUseCase)).Methods("GET")
    r.HandleFunc("/api/v1/users/{id}", GetUser(userUseCase)).Methods("GET")
    r.HandleFunc("/api/v1/users", CreateUser(userUseCase)).Methods("POST")
    r.HandleFunc("/api/v1/users/{id}", UpdateUser(userUseCase)).Methods("PUT")
    r.HandleFunc("/api/v1/users/{id}", DeleteUser(userUseCase)).Methods("DELETE")
    
    return r
}

3. Документация API (OpenAPI/Swagger)

В современных проектах описание API часто выносится в спецификацию OpenAPI (ранее Swagger), которая находится:

  • В отдельном файле swagger.yaml или swagger.json в корне проекта.
  • Генерируется автоматически из аннотаций в коде с помощью инструментов типа swaggo/swag.

Пример структуры:

├── docs/
│   ├── swagger.yaml         # ручное описание API
│   └── swagger.json
└── internal/
    └── transport/
        └── http/
            └── handlers/
                └── user_handler.go  # с аннотациями swag

4. Интерфейсы входа (Input Ports)

В чистой архитектуре API также косвенно описывается через интерфейсы Use Case (сценариев использования), которые определяют контракты для внешних взаимодействий:

// internal/usecase/user_usecase.go
package usecase

import "myapp/internal/entity"

type UserUseCase interface {
    GetUser(id string) (*entity.User, error)
    CreateUser(user *entity.User) error
    UpdateUser(user *entity.User) error
    DeleteUser(id string) error
    ListUsers() ([]*entity.User, error)
}

Ключевые принципы расположения API

  1. Инверсия зависимостей — API зависит от внутренних сценариев использования, а не наоборот.
  2. Изоляция изменений — изменения в фреймворке (например, переход с Echo на Gin) затрагивают только транспортный слой.
  3. Явное описание — все эндпоинты должны быть четко задокументированы в коде или спецификации.
  4. Верификация на уровне компиляции — в Go использование интерфейсов обеспечивает проверку соответствия API бизнес-логике.

Практические рекомендации для Go-разработчиков

  • Используйте отдельный пакет transport для изоляции кода API.
  • Внедряйте зависимости через интерфейсы, а не конкретные реализации.
  • Документируйте API с помощью автоматической генерации Swagger.
  • Тестируйте обработчики HTTP с помощью table-driven tests и моков use case.
  • Выносите валидацию входных данных на уровень обработчиков или создавайте отдельный слой DTO (Data Transfer Objects).

Пример полной цепочки обработки запроса

// internal/transport/http/handlers/user_handler.go
package handlers

import (
    "encoding/json"
    "net/http"
    "myapp/internal/usecase"
)

type UserHandler struct {
    userUseCase usecase.UserUseCase
}

func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
    // 1. Извлечение параметров из запроса
    id := mux.Vars(r)["id"]
    
    // 2. Вызов Use Case (бизнес-логики)
    user, err := h.userUseCase.GetUser(id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }
    
    // 3. Преобразование в ответ
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

Таким образом, в чистой архитектуре на Go описание поддерживаемых API находится на внешнем слое (transport layer), но тесно связано с интерфейсами сценариев использования (use case interfaces) через механизм инверсии зависимостей. Это обеспечивает гибкость, тестируемость и возможность независимой эволюции бизнес-логики и способов взаимодействия с внешним миром.