Структура backend сервиса на языке Go
Сервисы Ensi на Go строятся на Goravel и сохраняют те же организационные цели, что и PHP-сервисы:
- группировка кода по предметной области (модулю), а не по техническому слою на весь сервис;
- классы/типы меньше и сильнее следуют SRP.
Референсная реализация — catalog-cache-go. Ниже описана структура, которой следует придерживаться в новых Go-сервисах.
Общий обзор
app/
adapters/ # инфраструктура: БД-модели, Kafka, очередь, логи, метрики
common/ # общие HTTP-хелперы, search, ошибки, metrics
enums/ # enum'ы, сгенерированные из OpenAPI
facades/ # facades Goravel
modules/ # бизнес-модули (аналог Domain + Http Modules в PHP)
providers/ # регистрация провайдеров и HTTP-клиентов
bootstrap/ # сборка приложения, провайдеры, команды, jobs, kafka
config/ # конфигурация приложения и зависимостей
database/ # миграции и сидеры
resources/openapi/ # OAS3 спецификация API
routes/ # web, API и gRPC routes
tests/ # общие инструменты компонентного/OpenAPI тестирования
app/modules
Бизнес-логика и HTTP-слой модуля живут рядом в app/modules/{module}. Название модуля обычно во множественном числе и соответствует основной сущности: offers, products, brands.
Исключения:
common— сквозная функциональность сервиса (миграции сущностей, failed jobs, служебные команды);- инфраструктурные модули вроде
elastic/elastic_offers, если работа с индексом — отдельная предметная область; examples— демо-код для Kafka/queue/commands, не продакшен-логика.
app/modules/{module}
Типичный набор пакетов внутри модуля:
| Пакет | Назначение |
|---|---|
handlers | HTTP-контроллеры (точка входа API) |
actions | бизнес-действия с методом Execute |
queries | контракт search/filter/sort/include для списков |
mappers | преобразование adapters/db моделей в API DTO |
dto | request/response структуры |
tests | компонентные тесты эндпоинтов модуля |
commands | artisan-команды, относящиеся к модулю |
jobs | фоновые задачи очереди |
kafka | обработчики сообщений Kafka |
factories | фабрики запросов для тестов |
handlers
Handler принимает HTTP-запрос, валидирует его, вызывает action и формирует ответ. Он не содержит бизнес-логики и не ходит в БД напрямую. Ответ и ошибки собирают хелперами из app/common/http — см. HTTP-ответы и ошибки.
func (c *OffersController) Search(ctx http.Context) http.Response {
var req commondto.SearchRequest
if failResponse := commonhttp.Validate(ctx, &req); failResponse != nil {
return failResponse
}
result, err := actions.NewSearchOffersAction().Execute(ctx.Context(), req.Params())
if err != nil {
return commonhttp.Error(ctx, "ServerError", err)
}
return commonhttp.Page(ctx, result.Data, result.Pagination)
}
actions
Action — аналог Action-классов в PHP: осмысленное самостоятельное действие с публичным методом Execute. Action не должен знать про HTTP/Kafka-транспорт: на вход получает context.Context и типизированные параметры/DTO, на выход — результат или ошибку.
func (a *SearchOffersAction) Execute(ctx context.Context, params search.Params) (*commondto.SearchResult[dto.Offer], error) {
query := facades.Orm().WithContext(ctx).Query().Model(&db.Offer{})
data, pagination, err := search.Execute(query, queries.Offers(), params, mappers.OfferFromModel)
// ...
}
queries
Для search-эндпоинтов модуль описывает публичный SQL-контракт: доступные includes, sorts и filters. Общий движок лежит в app/common/search.
mappers
Mappers отделяют ORM-модели (app/adapters/db) от API DTO. Это позволяет менять структуру хранения, не ломая контракт ответа, и учитывать include при сборке ответа.
dto
DTO — структуры запроса/ответа API. Общие search-структуры лежат в app/common/dto.
app/adapters
Инфраструктурный слой, общий для всего сервиса:
adapters/db— ORM-модели и фабрики моделей (аналог Eloquent Models из PHP Domain). Модели не раскладываются по модулям: одна таблица — один файл вadapters/db. Подробнее: работа с базой данных;adapters/kafka— клиент, registry, supervisor consumers/producers. Как пользоваться: работа с Kafka;adapters/queue,adapters/schedule— обвязка воркеров очереди и планировщика. Про очереди: работа с очередями;adapters/logging,adapters/prometheus,adapters/observability— логирование и метрики. Про логи: логирование; про Prometheus: метрики;
Бизнес-модули зависят от adapters, но adapters не должны зависеть от конкретного HTTP-слоя модулей.
app/common
Общие переиспользуемые компоненты без привязки к конкретному домену:
http— валидация, единообразные ответы и ошибки, middleware;search— выполнение search-запросов поqueries.Definition;dto,collections,metrics, ошибки приложения.
Служебные HTTP-ручки вроде healthcheck/OpenAPI UI лежат в app/common/handlers и подключаются из routes/web.go.
routes
Роуты живут в корневой директории routes/:
api.go— точка входа API, вызывает сгенерированную регистрацию;api_gen.go— сгенерированные API-роуты (DO NOT EDIT);web.go— служебные маршруты (health, OpenAPI UI);
Сгенерированные роуты создают контроллеры из app/modules/{module}/handlers и вешают их на /api/v1/....
resources/openapi
Описание API в OAS3 хранится в коде сервиса и является источником генерации серверного кода и клиентов.
resources/openapi
├── index.yaml
├── common_parameters.yaml
├── offers
│ ├── offers_paths.yaml
│ └── schemas
│ └── offers.yaml
└── products
├── products_paths.yaml
└── schemas
└── products.yaml
resources/openapi/index.yaml — главный файл спецификации. Параметры генерации — в .ensi-openapi-gen.yaml в корне сервиса.
Генерация серверных заготовок — CLI ensi-gog server (подробнее: генератор ensi-gog):
ensi-gog server
Ожидаемые артефакты:
| Артефакт | Куда |
|---|---|
| API-роуты | routes/api_gen.go |
| Handlers | app/modules/{module}/handlers/ |
| DTO / FormRequest | app/modules/{module}/dto/ |
| Enum'ы | app/enums/ |
| Фабрики запросов | app/modules/{module}/factories/ |
| Тестовые заготовки | app/modules/{module}/tests/ |
bootstrap и providers
bootstrap/— сборка приложения: список провайдеров, регистрация commands/jobs/kafka/schedule/seeders;app/providers/— провайдеры сервиса, в т.ч.providers/clientsдля HTTP-клиентов к другим сервисам Ensi;config/иconfig/ensi_clients/— конфигурация приложения и внешних клиентов.
database
Миграции и сидеры Goravel:
database/migrationsdatabase/seeders
Тесты
Подробнее об организации файлов и типичных сценариях — рекомендации к написанию автотестов на Go.
Общие инструменты OpenAPI/component-тестов лежат в tests/ в корне сервиса. Компонентные тесты модулей — рядом с кодом: app/modules/{module}/tests/{resource}/.
Запуск:
elc go test ./... --env=.env.testing
Соответствие PHP-структуре
| PHP (Laravel) | Go (Goravel) |
|---|---|
app/Domain/{Domain}/Actions | app/modules/{module}/actions |
app/Domain/{Domain}/Models | app/adapters/db |
app/Http/ApiV1/Modules/{Module}/Controllers | app/modules/{module}/handlers |
.../Requests + .../Resources | app/modules/{module}/dto + mappers |
.../Queries | app/modules/{module}/queries |
public/api-docs/v1 | resources/openapi |
app/Http/ApiV1/routes.php (generated) | routes/api_gen.go |