Сервис заметок на Go с продвинутой реализацией gRPC и protobuf: unary-методы, server-client-bidi стримы, интерцепторы, валидация запросов на уровне .proto, ошибки с деталями, HTTP-доступ через gRPC-Gateway, Swagger UI и собственный protoc-плагин.
- 2. О проекте
- 3. Используемые технологии
- 4. Что реализовано в проекте
- 4.1 Базовый сервис заметок
- 4.2 Архитектура и хранение данных
- 4.3 Логирование и авторизация через интерцепторы
- 4.4 Настройка параметров gRPC-сервера
- 4.5 Валидация через protobuf
- 4.6 Ошибки с деталями
- 4.7 Серверный стриминг
- 4.8 Клиентский стриминг
- 4.9 Двунаправленный стриминг
- 4.10 Стрим-интерцептор и oneof-ошибки в стриме
- 4.11 HTTP, gRPC-Gateway, Swagger и CORS
- 4.12 Два HTTP-пути в проекте и WebSocket для стримов
- 4.13 Кастомный protoc-плагин
protoc-gen-fast-equal
- 5. API документация
- 6. Структура проекта
- 7. Локальная развертка
- 8. Команды Makefile
gRPC-notes — это сервис заметок, где основной API построен на gRPC и protobuf.
Проект показывает не только базовые CRUD-запросы, но и более глубокие возможности:
- цепочки unary и stream интерцепторов;
- server/client/bidi стриминг;
- проверка данных через правила прямо в
.proto; - понятная передача ошибок с деталями;
- доступ к API как по gRPC, так и по HTTP через gRPC-Gateway;
- WebSocket-обертка для стримов в web-сценариях;
- собственный плагин для генерации методов сравнения protobuf-структур.
- Go
- gRPC
- Protocol Buffers
- Unary, Server Streaming, Client Streaming, Bidirectional Streaming
- gRPC Interceptors
- Protovalidate (
buf.validate) - gRPC-Gateway
- OpenAPI/Swagger
- Chi Router
- CORS middleware
grpc-websocket-proxy- Docker / Docker Compose
- Makefile
- easyp (generate/lint/breaking)
- custom plugin:
protoc-gen-fast-equal
Реализован protobuf-контракт с одним сервисом NoteAPI и unary-методами:
- создание заметки;
- получение одной заметки;
- получение списка заметок;
- удаление заметки.
Для удобной работы с проектом добавлен Makefile с командами запуска и генерации.
Слои разделены:
handler— принимает запросы;usecase— выполняет бизнес-логику;repository— работает с данными.
Потокобезопасное in-memory хранилище:
- данные лежат в
map; - доступ защищен
sync.RWMutex; - параллельные чтение/запись работают корректно.
Сервер использует grpc.ChainUnaryInterceptor.
Реализовано:
- интерцептор логирования unary-запросов:
- начало вызова;
- имя метода;
- длительность выполнения;
- итог (успех/ошибка);
- интерцептор авторизации unary-запросов:
- чтение metadata из контекста;
- проверка
authorization; - ошибка
Unauthenticated, если токен не прошел проверку.
Сервер запускается с параметрами соединения (через grpc.ServerOption), чтобы лучше контролировать работу под нагрузкой:
- параметры keepalive (
Time,Timeoutи связанные настройки); - ограничение/контроль поведения соединений через конфиг.
Правила проверки данных описаны прямо в .proto:
- обязательные поля;
- минимальная/максимальная длина;
- проверка UUID;
- дополнительные message-правила.
В Go-коде выполняется protovalidate.Validate(...), поэтому не нужно писать много ручных if-проверок.
Ошибки возвращаются не только кодом, но и дополнительными деталями:
- используется gRPC статус с
WithDetails; - добавлено protobuf-сообщение
ErrorDetails; - клиент может получить не просто «ошибка», а понятную причину.
SubscribeToEvents:
- после подключения сразу отправляется health/welcome сообщение;
- при создании новых заметок клиент получает событие;
- при отключении клиента стрим завершается корректно.
UploadMetrics:
- клиент отправляет поток чисел;
- сервер накапливает значения;
- после завершения потока возвращает итоговую сумму.
Chat:
- обмен сообщениями в обе стороны в одном стриме;
- чтение и отправка работают асинхронно (горутины);
- используется
correlation_id, чтобы связывать ответы с исходными сообщениями.
Реализован stream-интерцептор:
- перехватывает сообщения стрима;
- логирует
RecvMsgиSendMsg.
В чате реализована передача бизнес-ошибки без закрытия соединения:
- сообщение использует
oneof; - один из вариантов —
google.rpc.Status.
Сервис доступен по HTTP через gRPC-Gateway:
- в
.protoдобавленыgoogle.api.httpаннотации; - сгенерированы gateway-файлы и OpenAPI/Swagger;
- поднят HTTP-сервер для JSON-запросов;
- подключен Swagger UI;
- добавлен CORS middleware для браузера.
В проекте есть два пути работы по HTTP:
- Самописные HTTP-ручки (
/notes/v1/...)
- отдельные хендлеры;
- полезно для полного ручного контроля HTTP-логики.
- gRPC-Gateway (
/gen/v1/...)
- маршруты автоматически следуют protobuf-контракту;
- добавлена WebSocket-обертка (
wsproxy.WebsocketProxy) для стриминговых сценариев в web.
В репозитории есть собственный protoc-плагин:
- анализирует protobuf messages;
- генерирует
*_fast_equal.pb.go; - добавляет метод
IsEqual(msg *T) boolдля быстрого сравнения.
Сервис: api.notes.v1.NoteAPI
Create(NoteCreateRequest) returns (Note)GetByID(NoteIDRequest) returns (Note)GetMulti(google.protobuf.Empty) returns (NoteList)DeleteByID(NoteIDRequest) returns (Note)
SubscribeToEvents(Empty) returns (stream EventResponse)— server streamingUploadMetrics(stream MetricRequest) returns (SummaryResponse)— client streamingChat(stream Message) returns (stream Message)— bidirectional streaming
Базовый префикс: /gen/v1
POST /gen/v1/notesGET /gen/v1/notes/{id}GET /gen/v1/notesDELETE /gen/v1/notes/{id}GET /gen/v1/notes/subscribePOST /gen/v1/notes/metrics/uploadPOST /gen/v1/notes/chat
Swagger:
- UI:
/gen/v1/swagger/ - спецификации:
/gen/v1/swagger/specs/...
Основные сообщения API:
NoteCreateRequestNoteIDRequestNoteNoteListEventResponse(oneofдля события/health)MetricRequestSummaryResponseMessage(correlation_id+oneof payload)ErrorDetails(детали ошибок)
- Авторизация проверяется по
authorizationmetadata/header. - Валидация запросов выполняется по правилам в
.proto. - При ошибках возвращаются корректные gRPC-коды (
InvalidArgument,NotFound,FailedPrecondition,Unauthenticated,Internal). - В ряде случаев передаются дополнительные details для клиента.
cmd/app— запуск gRPC-сервераcmd/client— запуск HTTP-слояapi/notes/v1— protobuf-контрактыpkg/api/notes/v1— сгенерированный код protobuf/gRPC/gatewayinternal/app— backend-слои (config, handler, usecase, repository, middleware, server)internal/client— HTTP/gateway-слои (router, handler, gateway, middleware, server)docs/api/notes/v1— Swagger JSONstatic/swagger— встроенные swagger-статические файлыprotoc-gen-fast-equal— исходники кастомного плагинаdeploy/app,deploy/client— docker-конфигурация
- Go 1.23+
- Docker + Docker Compose
- protoc (если нужна ручная генерация)
После клонирования репозитория:
go mod download
go mod tidyУстановка инструментов генерации:
make bin-depsИспользуются два env-файла:
deploy/app/.env— настройки gRPC backenddeploy/client/.env— настройки HTTP/gateway
Пример deploy/app/.env:
GRPC_PORT=50051
MAX_CONNECTION_IDLE=15s
MAX_CONNECTION_AGE=30s
MAX_CONNECTION_AGE_GRACE=5s
TIME=10s
TIMEOUT=5s
CAPACITY=10Что означает:
GRPC_PORT— порт gRPC сервераMAX_CONNECTION_IDLE— время простоя соединенияMAX_CONNECTION_AGE— максимальное время жизни соединенияMAX_CONNECTION_AGE_GRACE— мягкий период завершения соединенияTIME— интервал keepalive pingTIMEOUT— ожидание ответа на pingCAPACITY— емкость буфера event bus
Пример deploy/client/.env:
CLIENT_HOST=0.0.0.0
CLIENT_PORT=8080
GRPC_HOST=service-notes
GRPC_PORT=50051Что означает:
CLIENT_HOST— адрес HTTP сервераCLIENT_PORT— порт HTTP сервераGRPC_HOST— адрес gRPC backend для подключенияGRPC_PORT— порт gRPC backend
- Создайте/заполните:
deploy/app/.envdeploy/client/.env
- Запустите сервисы:
make run- Доступность:
- gRPC:
localhost:50051 - HTTP:
http://localhost:8080 - Swagger UI:
http://localhost:8080/gen/v1/swagger/
- Подготовьте переменные окружения (через
.envили export). - Запустите gRPC backend:
go run ./cmd/app- Запустите HTTP слой:
go run ./cmd/clientmake bin-deps
make generateДополнительно:
make lint
make breakingmake bin-deps— установить инструменты генерацииmake generate— сгенерировать protobuf/gRPC/gateway/swagger кодmake lint— проверить proto-контрактыmake breaking— проверить совместимость контрактовmake run— запустить сервисы в Dockermake down— остановить сервисы