В какой папке лежит транспортный слой
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Транспортный слой в архитектуре Go-приложения
Транспортный слой в архитектуре Go-приложения — это уровень, который отвечает за взаимодействие с внешним миром: прием HTTP-запросов, обработку gRPC-вызовов, работу с очередями сообщений или сокетами. В чистой архитектуре или многослойной (layered) архитектуре этот слой обычно располагается на самом верхнем уровне, поскольку он является точкой входа для внешних запросов.
Стандартная структура проекта в Go
Типовая структура проекта на Go часто следует соглашениям, принятым в сообществе. Папка, содержащая транспортный слой, может называться по-разному в зависимости от выбранного подхода:
/internal/transport— наиболее распространенный вариант в проектах, следующих принципам чистой архитектуры или гексагональной архитектуры. Эта папка находится внутри директории/internal, что ограничивает доступ к коду извне (согласно правилам Go)./apiили/pkg/api— используется, когда основной фокус на HTTP API (например, REST или GraphQL). Внутри могут быть поддиректории для разных транспортных протоколов:/api/http,/api/grpc./delivery— термин из модели Clean Architecture (Uncle Bob), где слой доставки соответствует транспортному уровню./handlerили/handlers— исторически сложившееся название в сообществе Go, особенно в контексте веб-приложений (например, в фреймворке Gin).
Пример структуры с транспортным слоем
Рассмотрим пример структуры проекта, где транспортный слой четко отделен от бизнес-логики:
myapp/
├── cmd/
│ └── server/
│ └── main.go
├── internal/
│ ├── entity/
│ ├── usecase/
│ ├── repository/
│ └── transport/
│ ├── http/
│ │ ├── user_handler.go
│ │ └── middleware.go
│ └── grpc/
│ └── user_service.go
├── pkg/
└── go.mod
В этом примере транспортный слой находится в /internal/transport. Он разделен на поддиректории по протоколам: http и grpc.
Код примера HTTP-обработчика
Обычно в файлах транспортного слоя определяются обработчики (handlers), которые преобразуют HTTP-запросы в вызовы случаев использования (use cases). Вот типичный пример:
package http
import (
"encoding/json"
"net/http"
"myapp/internal/usecase"
)
type UserHandler struct {
userUseCase usecase.UserUseCase
}
func NewUserHandler(uuc usecase.UserUseCase) *UserHandler {
return &UserHandler{userUseCase: uuc}
}
func (h *UserHandler) GetUserByID(w http.ResponseWriter, r *http.Request) {
userID := r.PathValue("id")
user, err := h.userUseCase.GetByID(r.Context(), userID)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
Ключевые моменты:
- Изоляция: Транспортный слой не должен содержать бизнес-логику. Он только делегирует вызовы в слой use cases.
- Зависимости: Транспортный слой зависит от слоя usecase, но не наоборот. Это соблюдает принцип инверсии зависимостей.
- Маршрутизация: Обычно настройка маршрутов (роутинг) также находится в этом слое или в близкой к нему точке (например, в
cmd/server). - Преобразование данных: Одна из главных задач — маппинг DTO (Data Transfer Objects): преобразование внешних запросов во внутренние структуры и обратно.
Альтернативные подходы
В некоторых фреймворках или подходах транспортный слой может быть организован иначе:
/cmd/api— в минималистичных проектах весь транспорт может находиться прямо в директории команды.- Плоская структура — в небольших приложениях иногда используют плоскую структуру, где handlers лежат в корневой папке проекта (не рекомендуется для больших проектов).
Вывод
Таким образом, папка транспортного слоя в Go-проекте чаще всего называется /internal/transport, но может варьироваться в зависимости от архитектурных предпочтений команды. Важно не конкретное название, а соблюдение принципа: транспортный слой должен быть отделен от бизнес-логики и служить исключительно для взаимодействия с внешними клиентами. Эта изоляция позволяет легко менять протоколы (например, с HTTP на gRPC) без изменений в ядре приложения.