Репозиторий содержит пример построения полноценного сервиса на Go с использованием генерации кода по OpenAPI-спецификации через ogen. В проекте демонстрируется:
- Генерация серверной и клиентской частей из единой спецификации.
- Реализация бизнес-логики с соблюдением принципов чистой архитектуры.
- Использование кастомного форка ogen с дополнительными возможностями.
- Контейнеризация через Docker Compose, включая Swagger UI для интерактивной документации.
Склонируйте репозиторий и поднимите все сервисы:
git clone https://github.com/J0hnLenin/ogen-example
cd ./ogen-example
docker compose up --buildПосле запуска будут доступны:
- Сервер API –
http://localhost:8000/api/v1 - Swagger UI –
http://localhost:8080 - Клиент-генератор
Спецификация OpenAPI описывает CRUD-операции над сущностью Игрок.
{
"id": 1,
"name": "Alice",
"score": 95.5
}| Метод | Путь | Описание |
|---|---|---|
| GET | /players |
Получить список всех игроков |
| GET | /players/{id} |
Получить игрока по ID |
| POST | /players |
Создать нового игрока |
| PUT | /players/{id} |
Полностью обновить игрока |
| PATCH | /players/{id} |
Частично обновить игрока |
| DELETE | /players/{id} |
Удалить игрока |
Все эндпоинты обслуживаются с префиксом /api/v1.
Проект использует форк github.com/J0hnLenin/ogen с дополнительными расширениями. Перед генерацией кода необходимо собрать бинарную версию утилиты.
- Клонирование форка
git clone https://github.com/J0hnLenin/ogen
cd ogen- Сборка бинарного файла
go build -o ogen ./cmd/ogenИли установите в $GOPATH/bin:
go install ./cmd/ogen- Проверка
ogen --versionВ рамках проекта в кастомный форк ogen были добавлены расширения, позволяющие гибко управлять генерируемой документацией и группировкой операций.
Основные изменения описаны в pull request.
-
Поддержка расширения
x-description
Добавлено новое полеadditionalDescriptionдля операций (Operation), которое парсится из расширенияx-descriptionв OpenAPI-спецификации. Это позволяет добавить дополнительный поясняющий текст к операции, который будет включён в сгенерированную документацию (GoDoc) наряду со стандартнымиsummaryиdescription.Использование в спецификации:
/players: get: summary: Получить всех игроков description: Возвращает массив объектов Player x-description: "Порядок может быть любым"
В сгенерированном коде метод
Handler.GetPlayersполучит полный комментарий, включая основное описание и дополнительный текст. -
Адаптация генератора GoDoc
МетодOperation.GoDoc()модифицирован так, что если заполнено полеAdditionalDescription, оно добавляется после основного описания с пустой строкой для разделения.
| Файл | Изменения |
|---|---|
gen/ir/operation.go |
Добавлено поле AdditionalDescription, обновлён метод GoDoc. |
gen/gen_operation.go |
Чтение поля XAdditionalDescription из openapi.Operation. |
openapi/parser/parse_path_item.go |
Добавлена функция parseAdditionalDescription и константа xAdditionalDescription. |
openapi/operation.go |
Добавлено поле XAdditionalDescription в структуру Operation. |
openapi/parser/parse_path_item_test.go |
Добавлены unit-тесты для нового расширения. |
Новые возможности покрыты тестами, проверяющими как наличие, так и отсутствие расширения x-description в спецификации.
Примечание: Все изменения совместимы с предыдущими версиями спецификаций – поле является опциональным.
Подробный diff доступен в pull request
ogen --target=./server/internal/api/playersapi \
--package=playersapi \
--config ./api/players_api/server.ogen.yml \
./api/players_api/openapi.ymlogen --target=./client/internal/api/playersapi \
--package=playersapi \
--config ./api/players_api/client.ogen.yml \
./api/players_api/openapi.ymlСгенерированные пакеты содержат:
- Интерфейс
Handler(для сервера) иClient(для клиента). - Все DTO-структуры (запросы/ответы).
- HTTP‑маршрутизацию и сериализацию.
Сервер реализует бизнес-логику и обрабатывает входящие HTTP-запросы.
server/
├── cmd/app/ # точка входа
├── internal/
│ ├── api/
│ │ └── playersapi/ # сгенерированный ogen-код
│ │ └── playersapiseive/ # обёртка над api
│ ├── config/ # загрузка конфига
│ ├── bootstrap/ # запуск c слоёв сервера
│ ├── models/ # доменные модели
│ ├── services/ # бизнес-логика (PlayerService)
│ └── storage/ # реализация хранилища (in-memory)
playersapi– полностью сгенерированный транспортный слой.playersserviceapi– адаптер, реализующий интерфейсHandlerи делегирующий вызовы вPlayerService.services/playerservice– бизнес-логика, независимая от HTTP.storage/memstorage– in-memory хранилище для игроков.bootstrap– собирает все зависимости и запускает HTTP-сервер с CORS и graceful shutdown.
server | 2026/07/24 11:14:13 Server listen: 0.0.0.0:8000
server | [cors] 2026/07/24 11:14:16 Handler: Actual request
server | [cors] 2026/07/24 11:14:16 Actual request no headers added: missing origin
server | [cors] 2026/07/24 11:14:52 Handler: Actual request
server | [cors] 2026/07/24 11:14:52 Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[http://localhost:8080] Vary:[Origin]]
...
Клиент периодически генерирует случайные данные и отправляет запросы на сервер, демонстрируя работу сгенерированного клиента.
client/
├── cmd/app/ # точка входа
├── internal/
│ ├── api/
│ │ ├── playersapi/ # сгенерированный ogen-клиент
│ │ └── clientservice/ # обёртка над клиентом с логированием
│ ├── config/ # загрузка конфига
│ ├── bootstrap/ # инициализация и запуск цикла генерации
│ └── gen/ # генератор случайных данных (имена, очки)
playersapi– сгенерированный клиент (структураClient, методы для каждого эндпоинта).clientservice– обёртка, вызывающая методы клиента и логирующая результаты.gen– генерация случайныхPlayerInputиPlayerPartial.bootstrap– создание клиента, запуск бесконечного цикла с таймером, выполнение случайных операций.config– загрузка параметров (URL сервера, интервал, batch size).
client | 2026/07/24 11:01:42 Client started. Server: http://server:8000/api/v1, interval: 5s
client | 2026/07/24 11:02:18 [GET] Found 1 players
client | 2026/07/24 11:02:18 - ID=1, Name=Player-2, Score=53.78
client | 2026/07/24 11:02:19 [CREATE] ID=2, Name=Player-1, Score=18.56
client | 2026/07/24 11:02:20 [PATCH] ID=2, Name=Player-2, Score=18.56
client | 2026/07/24 11:02:22 [CREATE] ID=3, Name=Player-9, Score=13.67
client | 2026/07/24 11:02:23 [GET] Found 3 players
client | 2026/07/24 11:02:23 - ID=2, Name=Player-2, Score=18.56
client | 2026/07/24 11:02:23 - ID=3, Name=Player-9, Score=13.67
client | 2026/07/24 11:02:23 - ID=1, Name=Player-2, Score=53.78
client | 2026/07/24 11:02:24 [GET] Found 3 players
client | 2026/07/24 11:02:24 - ID=1, Name=Player-2, Score=53.78
client | 2026/07/24 11:02:24 - ID=2, Name=Player-2, Score=18.56
client | 2026/07/24 11:02:24 - ID=3, Name=Player-9, Score=13.67
client | 2026/07/24 11:02:25 [PATCH] ID=2, Name=Player-2, Score=99.26
client | 2026/07/24 11:02:26 [CREATE] ID=4, Name=Player-6, Score=25.86
client | 2026/07/24 11:02:27 [GET] Found 4 players
client | 2026/07/24 11:02:27 - ID=2, Name=Player-2, Score=99.26
client | 2026/07/24 11:02:27 - ID=3, Name=Player-9, Score=13.67
client | 2026/07/24 11:02:27 - ID=4, Name=Player-6, Score=25.86
client | 2026/07/24 11:02:27 - ID=1, Name=Player-2, Score=53.78
Конфигурационные файлы монтируются в контейнеры, поэтому изменения не требуют пересборки – достаточно перезапустить контейнер.
server/config.yml– настройки сервера (хост, порт, префикс).client/config.yml– настройки клиента (URL сервера, интервал).
Проект служит демонстрацией возможностей ogen и может использоваться как шаблон для быстрого старта.
