Где находится описание поддерживаемых API в чистой архитектуре?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Описание поддерживаемых 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
- Инверсия зависимостей — API зависит от внутренних сценариев использования, а не наоборот.
- Изоляция изменений — изменения в фреймворке (например, переход с Echo на Gin) затрагивают только транспортный слой.
- Явное описание — все эндпоинты должны быть четко задокументированы в коде или спецификации.
- Верификация на уровне компиляции — в 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) через механизм инверсии зависимостей. Это обеспечивает гибкость, тестируемость и возможность независимой эволюции бизнес-логики и способов взаимодействия с внешним миром.