Custom-зоны · 0.8.1

Backend: hooks, зависимости и собственный API

Добавьте бизнес-правила и интеграции через предусмотренные контракты.

На этой странице

Backend custom-зоны нужны для правил, которые зависят от вашего бизнеса: дополнительной проверки заказа, расчёта значения, обращения во внешнюю систему или собственного API. Модель, обычные CRUD-операции и контракты продолжает обновлять генератор.

В путях ниже ENTITY_NAME замените именем каталога вашей сущности, например product; EntityName в Go-коде — её сгенерированный тип, например Product. Это обозначения, а не файлы, которые нужно создавать с такими именами.

Где писать код

Файл Для чего
backend/internal/custom/ENTITY_NAME/hooks.go Логика в сценариях одной сущности
backend/internal/custom/app/composition.go Подключение клиентов, зависимостей и hooks проекта
backend/internal/custom/app/routes.go Собственные публичные и защищённые маршруты
backend/internal/app/ENTITY_NAME/service.go Сгенерированный контракт: читайте его, реализацию добавляйте в custom
backend/internal/generated/customcontracts/ Типы для подключения расширений через композицию

Изменить значение перед сохранением

Откройте существующий hooks.go. Он уже содержит NewHooks() и методы для включённых CRUD-операций. Изменяйте тело нужного метода, не добавляйте второе объявление с тем же именем.

Пример для сущности с обычным строковым полем Name, которое не переведено в Localized:

func (hooks) BeforeCreate(_ context.Context, value domain.EntityName) (domain.EntityName, error) {
    value.Name = strings.TrimSpace(value.Name)
    return value, nil
}

Замените EntityName реальным типом и добавьте импорт strings. Если поле nullable или Localized, его тип может быть *string: сначала обработайте nil. Тип поля смотрите в сгенерированной модели, а не угадывайте по подписи в UI.

Hook Когда вызывается
BeforeCreate, BeforeUpdate До вызова записи в репозиторий; могут изменить значение или вернуть ошибку
AfterCreate, AfterUpdate После операции репозитория
BeforeDelete Перед удалением; получает ключ записи
AfterList После чтения страницы записей
AfterGetByID После чтения одной записи

Набор методов зависит от операций сущности. Ошибка BeforeCreate останавливает создание. Ошибка AfterCreate сама по себе не отменяет уже выполненную запись: для общей транзакции требуется явно спроектированная custom-логика. Для неверного пользовательского ввода используйте контракт ошибок вашего app-пакета, например оборачивание ErrInvalidInput, чтобы HTTP-граница корректно классифицировала ответ.

Подключить внешнюю зависимость

В composition.go реализуйте Configure(ctx, dependencies). Возвращаемая композиция позволяет задать типизированные hooks и защищённые маршруты. Непустой hook в композиции заменяет fallback из NewHooks(); nil оставляет его.

dependencies.DB — общий пул приложения. Используйте его через прикладные интерфейсы и не закрывайте самостоятельно. Клиентов, созданных вами, завершайте через возвращаемый Cleanup(ctx). Контекст Configure предназначен для старта; для запросов используйте r.Context(), а для своего фонового процесса — отдельный отменяемый контекст с завершением в Cleanup.

Добавить свой API

Для маршрутов проекта предусмотрены RegisterPublicRoutes и RegisterProtectedRoutes в custom/app/routes.go. У сущности есть RegisterRoutes. Выбирайте точку по задаче, не редактируйте generated bootstrap.

Папка custom не выдаёт маршрутам права автоматически. В зависимостях маршрутов доступны RequireAuthenticated, RequireAdminOperation, RequireExternalUser и CurrentPrincipal. Примените подходящую проверку доступа на сервере; факт входа пользователя ещё не означает разрешение на любую операцию. Собственные правила выбора записей также должны выполняться на сервере.

После изменения проверьте конкретный сценарий и соберите backend. Новый custom-маршрут не появляется автоматически в сгенерированном OpenAPI: его контракт поддерживает ваша команда.

Далее: Расширения интерфейса и Рабочий цикл custom-разработки.