Содержание урока · 11 разделов
Начну с честной карты местности, потому что слово «установка» в мире protobuf традиционно пугает. Если вы проходили курс по gRPC, то помните тот квест: поставить protoc, положить плагины в PATH, угадать флаги --go_out и --go_opt, следить, чтобы пути в командах совпали с путями в go_package — весь этот разбор остался в уроке про кодогенерацию gRPC. В мире Connect подход тот же — proto-first, схема первична, код не пишут руками, — но сам механизм генерации за последние годы отполировали до двух коротких YAML-файлов и трёх команд. Автор Connect-а, компания Buf, сделала тулчейн buf ровно для того, чтобы «хоровод protoc-флагов» больше никому не приходилось танцевать. Этот урок — connect установка от первого go mod init до зелёного buf generate: разберём, из чего вообще состоит окружение Connect-проекта, поставим каждую деталь, соберём структуру каталогов и проверим, что схема notes.v1 из первого урока превращается в рабочий Go-код.
Три части инструментария#
Прежде чем что-то ставить, разложим по полочкам, что именно мы ставим — путаница здесь источник половины ошибок. Часть первая — runtime-модуль connectrpc.com/connect: обычная Go-зависимость, которую импортирует ваш main.go и сгенерированный код. В нём живут handler, клиент, коды ошибок, конверты запросов и ответов — всё то, что мы видели на примерах первого урока. Часть вторая — генератор: программа buf плюс два плагина кодогенерации. Важный момент, который многие пропускают: плагины protoc-gen-go и protoc-gen-connect-go — это не библиотеки, а самостоятельные исполняемые файлы, написанные на Go; их устанавливает go install, и они должны быть видны в PATH, потому что buf вызывает их по имени. Третья часть — конфигурация: два YAML-файла, buf.yaml (паспорт модуля схем: где лежат proto-файлы и какие правила применять) и buf.gen.yaml (рецепт генерации: какие плагины запускать и куда класть результат). Отдельно проговорю, что НЕ нужно: модуль google.golang.org/grpc. Урок первый показал, что Connect-сервер живёт на net/http, — и зависимости от grpc-go у него нет, protobuf-модуль и стандартная библиотека покрывают всё.
Шаг 1: модуль и runtime-зависимость
GOmkdir notes && cd notes
go mod init example.com/notes
go get connectrpc.com/connect@latestПуть модуля example.com/notes — не случайная строка: именно на него ссылается опция go_package в схеме notes.v1 из первого урока, и именно от него будут отмеряться импорты сгенерированных пакетов. Если Go в системе ещё нет — начните с урока про установку Go в базовом курсе, там же разобраны go mod и устройство модулей. После go get в go.mod появится ровно одна новая require-строка: connectrpc.com/connect. Заметьте, чего в списке зависимостей нет: google.golang.org/grpc. Под капотом Connect — Protocol Buffers и net/http, мы это фиксировали в первом уроке, и go get здесь лишь подтверждает слова.
buf: один тулчейн вместо хоровода флагов#
buf — это CLI от той же компании Buf, что написала Connect, и в англоязычных туториалах этап «поставить и настроить buf» часто так и называют: buf setup. Умеет он четыре вещи, важные для нашего курса: generate — запуск плагинов кодогенерации по декларативному конфигу; lint — проверка стиля схем по наборам правил; breaking — проверка, что новая версия схемы не ломает старую; format — автоформатирование proto-файлов. Установка занимает минуты. На macOS и Linux удобнее всего формула Homebrew: brew install bufbuild/buf/buf. Если Homebrew нет, официальный скрипт кладёт бинарник в ~/.local/bin: curl -sSL "https://buf.build/install.sh" | bash. Есть и путь через Go, если вы принципиально держите всё в одном менеджере: go install github.com/bufbuild/buf/cmd/buf@latest. Проверка одна и та же: buf --version должен ответить версией — если shell не нашёл команду, дело почти всегда в PATH. Для Windows есть установщик через Scoop и PowerShell-скрипт, но в курсе мы будем показывать POSIX-варианты.
Что из перечисленного НЕ появится в зависимостях Connect-сервера после go get?
Плагины кодогенерации: два локальных бинарника#
Теперь плагины — те самые два исполнителя, которые превратят схему в код. Первый — protoc-gen-go: стандартный генератор message-типов от команды protobuf, тот же самый, что работал в gRPC-проектах. Второй — protoc-gen-connect-go: плагин проекта Connect, который создаёт handler-интерфейс, конструктор handler-а и типизированный клиент. Ставятся оба одинаково — go install по последнему тегу: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest и go install connectrpc.com/connect/cmd/protoc-gen-connect-go@latest. Здесь прячется самая частая ловушка всей установки: go install кладёт бинарники в каталог GOBIN, а при пустом GOBIN — в GOPATH/bin (обычно ~/go/bin). Если этот каталог не прописан в PATH, buf потом не найдёт плагины, и вы получите загадочное «program not found or is not executable». Проверьте заранее: go env GOBIN GOPATH, затем which protoc-gen-go и which protoc-gen-connect-go — обе команды должны показывать путь к файлам. Имена бинарников — не украшение: buf ищет их буквально по строке из конфига, поэтому переименовывать или переносить их нельзя.
buf.yaml: паспорт proto-модуля
GOversion: v2
modules:
- path: proto
lint:
use:
- STANDARD
breaking:
use:
- FILEЭто полный buf.yaml для нашего проекта, ничего лишнего. version: v2 — актуальный формат конфигурации buf; старые примеры в интернете с version: v1 работают, но новые проекты начинайте с v2. Секция modules объявляет proto-модуль: path: proto говорит, что корень схем — каталог proto/, и все пути внутри buf отсчитывает от него (файл proto/notes/v1/notes.proto для buf — это notes/v1/notes.proto). lint с набором STANDARD включает стартовые правила стиля схем — о том, как они ругаются, увидим на predict-задании ниже. Секция breaking задаёт политику проверки обратной совместимости — это тема отдельного урока про buf lint и breaking changes, пока достаточно того, что конфиг уже валиден и buf lint можно запускать.
buf.gen.yaml: рецепт генерации
GOversion: v2
plugins:
- local: protoc-gen-go
out: gen
opt: paths=source_relative
- local: protoc-gen-connect-go
out: gen
opt: paths=source_relativebuf.gen.yaml — файл, ради которого buf и придумывался: он заменяет длинные protoc-команды. local: protoc-gen-go — имя плагина, который buf вызовет как внешнюю программу (отсюда требование быть в PATH). out: gen — корень, куда пишется сгенерированный код. opt: paths=source_relative — опция плагина: путь выходного файла повторяет путь схемы, поэтому notes/v1/notes.proto ляжет в gen/notes/v1/notes.pb.go — и это ровно тот путь, который зашит в go_package схемы из первого урока. Второй блок делает то же для connect-плагина, с одним отличием в результате: он создаст подпакет notesv1connect. Порядок плагинов не важен, важны оба: без protoc-gen-go не будет message-типов, без protoc-gen-connect-go — handler-а и клиента.
Плагины не установлены, а buf generate уже запущен. Что произойдёт?
Прочитайте код и выберите, что он выведет:
$ buf generate
Failure: plugin "protoc-gen-connect-go": exit status 1:
exec: "protoc-gen-connect-go": executable file not found in $PATHСтруктура проекта: proto/, gen/, cmd/#
Окружение готово, время решить, где что лежит. Каноническая минимальная структура Connect-проекта держится на трёх каталогах с чёткими ролями. proto/ — единственное место, которое вы редактируете руками: схемы, и только схемы. gen/ — место сгенерированного кода: туда buf пишет файлы, и редактировать их нельзя категорически, потому что любая перегенерация затрёт правки. cmd/server/ — ваш код: реализация сервиса, монтирование handler-ов, запуск; в маленьких учебных проектах main.go можно держать и в корне модуля, но привычка cmd/server окупится сразу, как появится второй сервис или утилитный клиент. Рядом с ними — buf.yaml и buf.gen.yaml в корне, go.mod с модулем example.com/notes. Отдельный вечный спор — коммитить ли gen/ в git. Два лагеря: одни генерируют в CI и держат репозиторий чистым, другие коммитят — ради простых ревью и сборки без инструментов. Для учебного проекта коммитьте: меньше движущихся частей. Взрослую структуру — с несколькими модулями, линтерами и удалёнными плагинами — разберём отдельным уроком ближе к концу курса, а сейчас зафиксируйте три роли: схемы руками, генерат никогда, ваш код всегда.
Дерево после buf generate
GOnotes/
├── buf.yaml
├── buf.gen.yaml
├── go.mod
├── go.sum
├── proto/
│ └── notes/
│ └── v1/
│ └── notes.proto
├── gen/
│ └── notes/
│ └── v1/
│ ├── notes.pb.go
│ └── notesv1connect/
│ └── notes.connect.go
└── cmd/
└── server/
└── main.goСверьте своё дерево с этим — и обратите внимание на пару gen/notes/v1: там живут два Go-пакета. Пакет notesv1 (файл notes.pb.go) — message-типы Note, GetNoteRequest, CreateNoteRequest. Пакет notesv1connect (файл notes.connect.go) — интерфейс NoteServiceHandler, конструктор NewNoteServiceHandler и клиент NewNoteServiceClient. Почему два пакета, а не один: connect-пакет импортирует message-типы, и в одном каталоге Go такое не разрешит. Теперь откройте в памяти сервер из первого урока: он импортировал notesv1connect по пути example.com/notes/gen/notes/v1/notesv1connect — обещание «доведём notes.v1 до кода» выполнено, эти файлы больше не заглушки из примера, они у вас на диске.
Какой файл генерирует protoc-gen-connect-go и что в нём лежит?
Старый путь: protoc с флагами#
Справедливости ради — buf не единственный вариант, и на существующих проектах вы встретите классический protoc. Компилятор ставится пакетом (brew install protobuf или apt install protobuf-compiler) и вызывается с двумя парами флагов: --go_out и --connect-go_out указывают, куда писать, а --go_opt=paths=source_relative и --connect-go_opt=paths=source_relative — как формировать пути. Поисковый запрос protoc connect почти всегда означает ровно эту пару флагов --connect-go_out: так ищут способ подключить connect-генерацию к существующему protoc-пайплайну, и это легитимный сценарий, если у вас уже настроен CI вокруг protoc и переписывать его ради buf-а никто не готов. Но для новых проектов аргументы за buf перевешивают: конфигурация лежит в файлах и версионируется, lint и breaking встроены в тот же тулчейн, а имена плагинов не растягиваются на три строки команды. Мой практический ориентир: protoc — когда вписываетесь в унаследованный пайплайн, buf — во всех остальных случаях, включая весь этот курс.
Тот же результат без buf: protoc
GOprotoc -I proto \
--go_out=gen --go_opt=paths=source_relative \
--connect-go_out=gen --connect-go_opt=paths=source_relative \
proto/notes/v1/notes.protoТа же генерация, что делал buf generate, вручную: -I proto задаёт каталог поиска импортов, каждая пара --_out/--_opt — плагин с настройками. Обратите внимание, сколько всего нужно помнить и повторять в каждом CI-скрипте: флаги, пути, имена плагинов. buf.gen.yaml хранит то же самое декларативно и запускается одним словом. Если команда protoc у вас отработала — хорошо, вы знаете запасной путь; файлы в gen/ будут идентичны buf-овским.
Инструментарий на одной карточке#
| Инструмент | Роль в проекте | Как ставится |
|---|---|---|
| Go | компилятор и тулчейн: на нём написаны плагины, buf и ваш сервер | пакетом ОС или с go.dev |
| connectrpc.com/connect | runtime: handler, клиент, коды ошибок, конверты запросов | go get в проект |
| buf | диспетчер генерации + lint/breaking/format схем | brew, install-скрипт или go install |
| protoc-gen-go | плагин: *.pb.go с message-типами | go install |
| protoc-gen-connect-go | плагин: *.connect.go с handler-ом и клиентом | go install |
| protoc | классический компилятор схем, альтернатива buf | brew / apt, опционален |
| google.golang.org/grpc | не нужен: сервер Connect живёт на net/http | — |
В схеме заменили package notes.v1 на просто notes и запустили buf lint. Что будет?
Прочитайте код и выберите, что он выведет:
syntax = "proto3";
package notes; // было notes.v1Восстановите buf.gen.yaml: куда писать сгенерированный код и какой плагин отвечает за handler и клиент.
Соберите путь от пустого каталога до сгенерированного кода notes.v1 — по порядку.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Интерактивы (тесты, «предскажи вывод», сборка по шагам, карточки) работают прямо на странице и дают XP, а вот buf, go и curl — только на вашей машине: сетевой код и кодогенерацию песочница сайта не исполняет, поэтому исполняемых блоков в курсе нет. Команды урока копируются по одной — к концу у вас будет рабочее окружение и сгенерированный код notes.v1.
Что именно проверяет команда buf lint?
Проверяем установку#
Финальный тест готовности — три команды. buf lint: если молчит (а buf молчалив при успехе, что поначалу сбивает с толку) — схема notes.v1 проходит правила STANDARD. buf generate: если ls gen/notes/v1 показывает notes.pb.go, а рядом каталог notesv1connect с notes.connect.go — кодогенерация работает end-to-end. И контрольный выстрел: grep NewNoteServiceHandler gen/notes/v1/notesv1connect/notes.connect.go должен найти конструктор — ту самую функцию, которую сервер из первого урока вызывал как данность. На этом окружение собрано полностью: runtime в go.mod, плагины в PATH, buf настроен двумя YAML-файлами, структура каталогов принята, notes.v1 превратилась в код. Если какая-то из трёх проверок не сошлась — вернитесь к order-заданию выше и сверьте порядок шагов; девяносто процентов проблем установки лечатся проверкой PATH и перечитыванием вывода buf, который пишет ошибки вполне внятно.
Карточки: инструментарий Connect-проекта
Что дальше по курсу#
Окружение собрано, но в gen/ лежит пока мёртвый код — интерфейсы, которые никто не реализует, и конструкторы, которые никто не вызывает. Следующий урок — «Первый Connect-сервис» (03-pervyj-servis) — оживает в три действия: добавим к проекту схему ElizaService, официальный hello world мира Connect-а, реализуем handler с ответами болтуна, соберём main с двумя сервисами на одном mux и сделаем первую curl-проверку по-настоящему запущенного сервера. Заодно выполним обещание первого урока: полностью разберём notes-сервер построчно — вместе с клиентом NewNoteServiceClient и проверкой кодов ошибок. Дальше по курсу: четвёртый урок спустит нас на уровень проводов и покажет, чем на байтах отличаются три протокола, шестой — ошибки и connect.NewError, седьмой — interceptors, девятый — браузерных клиентов на TypeScript. Если прото-синтаксис пока читается с трудом — вернитесь к курсу gRPC: схема proto3 там разобрана с нуля.
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Окружение Connect — три части: runtime-модуль connectrpc.com/connect (go get), два плагина кодогенерации (go install) и тулчейн buf с двумя YAML-конфигами.
- Плагины protoc-gen-go и protoc-gen-connect-go — исполняемые файлы в PATH: buf вызывает их по имени, ошибка «not found in PATH» — самая частая проблема установки.
- buf.yaml описывает модуль схем (path: proto) и наборы правил: lint STANDARD, breaking FILE; version: v2 — актуальный формат.
- buf.gen.yaml заменяет protoc-команды: local — имя плагина, out gen — куда писать, paths=source_relative — путь повторяет схему.
- Результат генерации: gen/notes/v1/notes.pb.go (пакет notesv1, message-типы) и gen/notes/v1/notesv1connect/notes.connect.go (handler, конструктор, клиент).
- Структура: proto/ — руками, gen/ — никогда (только перегенерация), cmd/server/ — ваш код; gen/ в учебном проекте коммитим.
- protoc с флагами --go_out/--connect-go_out — валидный запасной путь, но buf даёт конфиг в файлах, lint и breaking из коробки.
Домашнее задание
Соберите окружение по шагам урока и зафиксируйте результат: init модуля example.com/notes, go get connectrpc.com/connect, установка обоих плагинов с проверкой which, buf --version. Положите схему notes.v1 из первого урока в proto/notes/v1/notes.proto, создайте buf.yaml и buf.gen.yaml и добейтесь, чтобы buf lint молчал, а buf generate создал оба файла в gen/. Затем проверьте себя: grep NewNoteServiceHandler по notes.connect.go находит конструктор, а в go.mod нет строки google.golang.org/grpc. Напишите в заметки три свои ошибки из пути (почти у всех — PATH и пути в go_package) — это ваш чек-лист на будущее.
Личные заметкиПусто
Вопросы и ответы по уроку
Что нужно для установки Connect в Go-проект?
Три вещи: runtime-модуль connectrpc.com/connect через go get, плагины protoc-gen-go и protoc-gen-connect-go через go install (они должны быть в PATH) и тулчейн buf с конфигами buf.yaml и buf.gen.yaml. Модуль grpc-go не требуется.
buf обязателен или можно работать через protoc?
Можно и через protoc: флаги --go_out и --connect-go_out дают тот же результат. buf предпочтительнее для новых проектов — конфигурация в файлах, встроенные lint и breaking, единая точка запуска buf generate.
Почему сгенерировалось два пакета, notesv1 и notesv1connect?
protoc-gen-go создаёт message-типы (notes.pb.go), а protoc-gen-connect-go — отдельный пакет notesv1connect с handler-интерфейсом, конструктором и клиентом. Connect-пакет импортирует message-типы, поэтому в Go они живут в разных каталогах.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Сравните с альтернативами
Практический вопрос после первых уроков: а почему именно эта библиотека? Мы разобрали конкурентов по одним критериям, с кодом одной задачи рядом и персональным подбором под ваши приоритеты.
Изучайте дальше
Следующая ступень учебного пути
Fyne: десктопные и мобильные GUI на Go
Курс Fyne: окна, виджеты, контейнеры, canvas, темы, binding, сборка под мобильные и десктоп. 25 уроков и итоговый менеджер задач.
- Создавать окна и интерфейсы из виджетов
- Управлять компоновкой: Box, Grid, Form
- Рисовать примитивами canvas и строить свои виджеты
- Связывать данные через binding