Транспорты¶
Описание секций rest, grpc, kafka и cli.
Секция rest¶
Конфигурация REST API транспортов.
rest:
# OpenAPI сервер
- name: api
path: [./api/openapi.yaml]
generator_type: ogen
port: 8080
version: v1
health_check_path: /health
# Системные endpoints (метрики, health)
- name: system
generator_type: template
generator_template: sys
port: 9090
version: v1
# REST клиент для внешнего API
- name: payment_api
path: [./api/payment.yaml]
generator_type: ogen_client
auth_params:
transport: header
type: apikey
Поля¶
| Поле | Обязательно | Описание |
|---|---|---|
name |
Да | Имя транспорта |
path |
Для ogen/ogen_client | Пути к OpenAPI спецификациям |
generator_type |
Да | Тип генератора: ogen, template, ogen_client |
generator_template |
Для template | Имя шаблона (например, sys) |
generator_params |
Нет | Доп. параметры генератора (например, auth_handler) |
port |
Да (кроме sys) | HTTP порт |
version |
Да | Версия API (v1, v2, и т.д.) |
api_prefix |
Нет | Префикс URL для API |
health_check_path |
Нет | Путь для health check |
public_service |
Нет | Публичный сервис (без аутентификации) |
auth_params |
Нет | Параметры аутентификации (для ogen_client) |
instantiation |
Нет | static или dynamic (только для ogen_client) |
Типы генераторов¶
| Тип | Описание | Применение |
|---|---|---|
ogen |
Генерация сервера из OpenAPI 3.0 | Основные бизнес API |
template |
Шаблонная генерация | Health checks, метрики, кастомные endpoints |
ogen_client |
Генерация REST клиента | Вызов внешних API |
Параметры аутентификации¶
Для ogen_client можно настроить аутентификацию:
rest:
- name: external_api
generator_type: ogen_client
auth_params:
transport: header # Способ передачи (пока только header)
type: apikey # Тип аутентификации: apikey или bearer
Типы аутентификации:
| Тип | OnlineConf путь | Описание |
|---|---|---|
apikey |
{service_name}/transport/rest/{rest_name}/auth_params/apikey |
API key в заголовке |
bearer |
{service_name}/transport/rest/{rest_name}/auth_params/token |
Bearer token в заголовке Authorization |
Динамический режим инстанцирования (ogen_client)¶
По умолчанию REST-клиенты создаются один раз при старте приложения (static).
Режим dynamic позволяет создавать клиенты при каждом запросе:
rest:
- name: external_api
generator_type: ogen_client
instantiation: dynamic # Клиент создаётся при каждом вызове
applications:
- name: server
transport:
- name: external_api
config:
instantiation: dynamic # Override на уровне приложения
Когда использовать dynamic:
- URL внешнего API меняется динамически
- Нужна изоляция клиентов между запросами
- Тестирование с разными конфигурациями
Приоритет настроек:
application.transport[].config.instantiation(наивысший)rest[].instantiation(default для всех приложений)
Требования к OpenAPI-схеме (ogen)¶
При использовании generator_type: ogen в OpenAPI-спецификации обязательно должна быть определена схема ErrorDefault с точным набором полей. Генератор использует эту схему для обработки ошибок в сгенерированных файлах (error_response.go, handler.go, router.go).
Обязательная схема:
components:
schemas:
ErrorDefault:
required:
- code
- error
properties:
code:
type: integer
format: int32
error:
type: string
type: object
Ogen автоматически генерирует из этой схемы два Go-типа:
| Тип | Описание |
|---|---|
ErrorDefault |
Struct с полями Code (int32) и Error (string), плюс метод Encode(e) для сериализации через jx |
ErrorDefaultStatusCode |
Wrapper-struct с полями StatusCode (int) и Response (ErrorDefault), используется как возвращаемое значение NewError() |
Как использовать в спецификации:
Все endpoints должны ссылаться на ErrorDefault в default-ответе:
paths:
/item:
get:
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Item'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorDefault'
Имя схемы фиксировано
Сейчас имя ErrorDefault захардкожено в шаблонах генератора. Если в OpenAPI-спецификации схема ошибки называется иначе (например, Error, ApiError), сгенерированный код не скомпилируется. См. #12 о поддержке кастомных имён.
Workaround через after-marker код
Пока issue не закрыт, можно переопределить поведение ниже disclaimer-маркера. Обязательно добавьте ссылку на issue и TODO для удаления. Подробнее — в Регенерация: after-marker код как workaround.
Поддержка нескольких версий API¶
rest:
- name: api
path: [./api/v1.yaml]
generator_type: ogen
port: 8080
version: v1
- name: api
path: [./api/v2.yaml]
generator_type: ogen
port: 8080
version: v2
Генерируемая структура:
internal/app/server/transport/rest/api/
├── v1/
│ ├── handlers.go
│ └── router.go
└── v2/
├── handlers.go
└── router.go
Секция grpc¶
Конфигурация gRPC клиентов.
grpc:
- name: users
path: ./proto/users.proto
short: users
port: 9000
generator_type: buf_client
buf_local_plugins: false
Поля¶
| Поле | Обязательно | Описание |
|---|---|---|
name |
Да | Имя gRPC клиента |
path |
Да | Путь к .proto файлу |
short |
Нет | Короткое имя (для именования пакетов) |
port |
Да | gRPC порт |
generator_type |
Да | Тип генератора: buf_client |
buf_local_plugins |
Нет | Использовать локальные buf плагины |
instantiation |
Нет | static или dynamic (только для buf_client) |
Только клиенты
В текущей версии поддерживается только генерация gRPC клиентов (buf_client). Генерация серверов (buf_server) пока не реализована.
Динамический режим инстанцирования (buf_client)¶
По умолчанию gRPC-клиенты создаются один раз при старте приложения (static).
Режим dynamic позволяет создавать клиенты в рантайме через NewDynamicClient(ctx, address):
grpc:
- name: users
path: ./proto/users.proto
port: 9000
generator_type: buf_client
instantiation: dynamic # Клиент создаётся при каждом вызове
Что меняется в dynamic режиме:
- Клиент не регистрируется при старте (
SetClient) - Клиент не добавляется в Service struct
- Клиент не валидируется в
ValidateFor* - Вместо
NewClient()+Init()генерируетсяNewDynamicClient(ctx, address) - Адрес (host:port) передаётся как параметр, без OnlineConf
Когда использовать dynamic:
- Адрес gRPC сервера определяется в рантайме
- Нужна изоляция подключений между запросами
- Тестирование с разными конфигурациями
Секция kafka¶
Конфигурация Kafka producers и consumers.
kafka:
- name: events_producer
type: producer
driver: segmentio
client: main_kafka
events:
- name: user_events
schema: models.user
- name: order_consumer
type: consumer
driver: segmentio
client: main_kafka
group: my_group
events:
- name: order_events
Поля¶
| Поле | Обязательно | Описание |
|---|---|---|
name |
Да | Имя producer/consumer |
type |
Да | producer или consumer |
driver |
Нет | segmentio (default) или custom |
client |
Да | Имя клиента для OnlineConf пути |
group |
Для consumer | Consumer group |
events |
Да | Список событий |
Концепция Events¶
KafkaEvent— единица публикации/потребления сообщений- Event name используется для генерации Go методов
- Topic name по умолчанию совпадает с event name
- Topic можно переопределить через OnlineConf
Типизированные сообщения¶
Events могут ссылаться на JSON Schema:
jsonschema:
- name: models
schemas:
- id: user
path: ./user.schema.json
kafka:
- name: producer
type: producer
client: main_kafka
events:
- name: user_events
schema: models.user # Генерирует типизированный метод
OnlineConf пути для Kafka¶
| Путь | Описание |
|---|---|
{service}/kafka/{client}/brokers |
Список брокеров через запятую |
{service}/kafka/{client}/auth_type |
none, PLAIN, SCRAM-SHA-256, SCRAM-SHA-512 |
{service}/kafka/{client}/username |
SASL username |
{service}/kafka/{client}/password |
SASL password |
{service}/kafka/{client}/tls_enabled |
0 или 1 |
{service}/kafka/{client}/events/{event_name}/topic |
Override topic name |
Секция cli¶
Конфигурация CLI транспорта. CLI генерирует обработчики команд из YAML-спецификации — по аналогии с тем, как ogen генерирует REST handlers из OpenAPI.
cli:
- name: admin
path:
- ./commands.yaml # Спецификация CLI команд
generator_type: template
generator_template: cli
applications:
- name: admin-cli
cli: admin
driver: [postgres]
Поля¶
| Поле | Обязательно | Описание |
|---|---|---|
name |
Да | Имя CLI транспорта |
path |
Нет | Путь к YAML-спецификации команд (commands.yaml) |
generator_type |
Да | template |
generator_template |
Да | cli |
Особенности CLI¶
- CLI эксклюзивен — приложение с CLI не может иметь REST/gRPC транспорты
- Один CLI на application
- Вызывает тот же Service — CLI handlers используют те же методы сервиса
- Может использовать драйверы
Принцип работы¶
./myapp <command> [arguments...]
# Примеры:
./myapp migrate up
./myapp user create --email admin@example.com
./myapp cache clear --all
Спецификация команд (commands.yaml)¶
Если указан path, генератор читает YAML-спецификацию и генерирует:
- Params structs — типизированные параметры для каждой команды
- UnimplementedCLI — стаб с default-реализацией (по аналогии с ogen/gRPC)
- registerCommands() — регистрация команд с flag parsing и валидацией
- Command/Subcommand structs — диспетчеризация команд и подкоманд
# commands.yaml
commands:
- name: user
description: "User management"
subcommands:
- name: create
description: "Create a new user"
flags:
- name: email
type: string
required: true
description: "User email"
- name: name
type: string
description: "User name"
- name: list
description: "List all users"
flags:
- name: limit
type: int
default: "100"
description: "Max results"
- name: ping
description: "Check connectivity"
- name: migrate
description: "Database migrations"
flags:
- name: dir
type: string
default: "up"
description: "Direction: up or down"
- name: steps
type: int
description: "Number of steps"
Правила спецификации:
- Команда может иметь
subcommandsИЛИ быть leaf-командой (без подкоманд) - Флаги могут быть у leaf-команд и у подкоманд
- Типы флагов:
string,int,bool,float64,duration required: true— генерируется валидация после парсингаdefault— значение по умолчанию (строка, парсится в нужный тип)
Генерируемый код¶
Из спецификации генерируется файл psg_handler_gen.go:
Params structs¶
Для каждой команды/подкоманды с флагами генерируется struct с типизированными параметрами:
type UserCreateParams struct {
Email string
Name string
}
type MigrateParams struct {
Dir string
Steps int
}
Имя: {Command}{Subcommand}Params (PascalCase). Если у команды нет флагов, Params struct не создаётся.
UnimplementedCLI¶
Стаб с default-реализацией — можно сразу компилировать проект без написания логики:
type UnimplementedCLI struct{}
func (UnimplementedCLI) RunUserCreate(ctx context.Context, params UserCreateParams) error {
return fmt.Errorf("command 'user create' is not implemented")
}
func (UnimplementedCLI) RunPing(ctx context.Context) error {
return fmt.Errorf("command 'ping' is not implemented")
}
Имя метода: Run{Command}{Subcommand} (PascalCase).
Пользовательский код¶
Пользователь создаёт файлы в том же пакете и переопределяет методы:
// user.go
package admin
func (h *Handler) RunUserCreate(ctx context.Context, params UserCreateParams) error {
user, err := h.GetService().CreateUser(ctx, params.Email, params.Name)
if err != nil {
return fmt.Errorf("failed to create user: %w", err)
}
fmt.Printf("User created: ID=%d\n", user.ID)
return nil
}
Аналогия с ogen
Паттерн идентичен ogen: spec → UnimplementedHandler → пользователь переопределяет нужные методы. Нереализованные команды возвращают ошибку "not implemented".
Без спецификации¶
Если path не указан, генерируется минимальный handler с закомментированным примером для ручной регистрации команд.
Сравнение CLI и Worker¶
| CLI | Worker |
|---|---|
| Запускается пользователем | Запускается с приложением |
| Выполняет одну команду | Работает непрерывно |
| Интерактивный | Автономный |
| Завершается после команды | Работает до shutdown |