---
title: "Введение в Connect RPC"
description: "Что такое Connect RPC простыми словами: почему gRPC не дружит с браузером, как один handler на net/http понимает три протокола и где Connect уместен."
course: "Connect: современный RPC от Buf"
url: "https://golangmaster.ru/courses/connect/lessons/01-vvedenie/"
published: "2026-09-19"
updated: "2026-09-21"
minutes: 15
---

# Введение в Connect RPC

*Курс «Connect: современный RPC от Buf», урок 1 из 25. ~15 минут. Обновлено 21.09.2026. Источник: https://golangmaster.ru/courses/connect/lessons/01-vvedenie/*

Что такое Connect RPC и зачем он появился, если gRPC уже решил проблему RPC в Go? У gRPC есть ахиллесова пята — браузер: из JavaScript обычный gRPC-сервер вызвать нельзя. Разберём, почему, что такое gRPC-Web и чем Connect от Buf отличается: один handler на net/http понимает сразу три протокола.

Начну с ситуации, в которой оказывается почти каждый, кто прошёл курс по gRPC. Сервис на google.golang.org/grpc радует: контракт в .proto, заглушки сгенерированы, дедлайны и стриминг работают, всё тестировалось. Потом приходит фронтенд-команда и спрашивает: «А можно нам те же методы прямо из браузера?» И здесь понижение температуры: нельзя. Браузерный JavaScript не умеет говорить по gRPC — ни fetch, ни XMLHttpRequest не дают доступа к HTTP/2-трейлерам, где gRPC хранит итоговый статус вызова. Дальше начинается черёд костылей: ручной REST-фасад, который дублирует логику и расходится с контрактом, или прокси Envoy с протоколом gRPC-Web, у которого свой список оговорок. В 2022 году компания Buf — та самая, что сделала тулчейн buf и Buf Schema Registry — открыла Connect: библиотеку, построенную ровно вокруг этой боли. Этот урок — connectrpc обзор в одном месте: сначала разберём, почему gRPC и браузер несовместимы, затем посмотрим на решение — один обработчик на net/http, который понимает Connect, gRPC и gRPC-Web одновременно, — а в конце честно обсудим, где Connect уместен, а где он лишний.

### Что такое Connect RPC

Connect — «slim library for building browser and gRPC-compatible HTTP APIs», как формулируют авторы: тонкая библиотека для построения браузерных и gRPC-совместимых HTTP API. Рецепт работы прежний, proto-first: пишете короткую Protocol Buffers-схему, реализуете логику приложения, а библиотека генерирует код, который делает сериализацию, маршрутизацию, компрессию и согласование форматов, плюс типизированный клиент. Для Go это модуль connectrpc.com/connect, официально рекомендуемый конструктор API поверх protobuf. Проект открыт в 2022 году под лицензией Apache 2.0 и развивается компанией Buf; кроме Go, есть реализации для TypeScript (пакет для браузера и Node), Kotlin, Swift, Dart и Python — экосистема уже мультиязычная, а не «Go-only». Ключевая идея всего фреймворка умещается в одну фразу из документации: handlers и clients поддерживают три протокола — gRPC, gRPC-Web и собственный протокол Connect. Схема одна, сервер один, порты и клиенты — по вкусу. В этом курсе мы изучим полный путь: установку с buf, первый сервис, протоколы, ошибки, interceptors, стриминг и браузерных клиентов.

### Почему gRPC не работает в браузере

Чтобы понять ценность Connect, нужно на минуту спуститься на уровень HTTP. gRPC ездит строго по HTTP/2 и активно использует его трейлеры — заголовки, которые сервер отправляет после тела ответа. Это не деталь реализации, а ядро дизайна: итоговый статус вызова (grpc-status) и сообщение об ошибке gRPC кладёт именно в трейлеры. У обычных HTTP-серверов статус живёт в первой строке ответа и известен до тела, у gRPC — в самом конце, потому что часть ошибок выявляется только когда ответ уже частично отослан. Теперь браузер. JavaScript-код не работает с HTTP напрямую: он говорит через Fetch API, а тот не отдаёт коду ни трейлеры, ни сырые HTTP/2-кадры. Сотрудники команды Connect в FAQ формулируют это жёстко и точно: многие HTTP-реализации, включая браузеры, трейлеры до сих пор не поддерживают — и потому никакой код в браузере не может говорить по протоколу gRPC. Заметьте, картина получается дурацкая: ответ физически пришёл, тело даже распарсилось, а фронтенд не может узнать, чем закончился вызов — успехом или ошибкой. Для API это не баг, а полный отказ: система, в которой нельзя узнать исход запроса, не годится.

### gRPC-Web: обходной путь с прокси

Первая попытка лечить это — протокол gRPC-Web, придуманный самой gRPC-командой. Идея простая до безобразия: вместо трейлеров закодировать служебную информацию в конец тела ответа. Трейлеров нет — браузеру они и не нужны. Но у gRPC-Web есть две оговорки, которые вы вспоминаете в самый неподходящий момент. Первая: чистые gRPC-серверы (grpc-go, grpc-java) по умолчанию gRPC-Web не говорят, поэтому между браузером и сервисом ставят прокси — обычно Envoy, — который переводит gRPC-Web в gRPC и обратно. Лишний hop, лишний деплой, лишняя точка, где что-то пойдёт не так. Вторая оговорка: gRPC-Web поддерживает только бинарный формат protobuf, поэтому в devtools браузера вы видите кашу из байтов вместо читаемого JSON — отлаживать неудобно. Со стримингом тоже не без клиники: серверный стриминг из браузера работает, а вот клиентский и двунаправленный — с серьёзными ограничениями, о которых честно предупреждают документации. Подытожу по-своему: gRPC-Web — это полумера, которая решает проблему трейлеров, но платит прокси и удобством разработки. Именно от этой полумеры Connect и отталкивается.

### gRPC, gRPC-Web и Connect: сравнение

| Критерий | gRPC | gRPC-Web | Connect |
| --- | --- | --- | --- |
| Транспорт | только HTTP/2 | HTTP/1.1 и HTTP/2 | HTTP/1.1 и HTTP/2 (bidi — только HTTP/2) |
| Трейлеры | обязательны: grpc-status живёт там | нет, закодированы в тело | не используются вовсе |
| Браузер напрямую | нет | да, если сервер умеет gRPC-Web | да, JSON из коробки |
| Прокси для чистого gRPC-сервера | не нужен | нужен, обычно Envoy | не нужен: handler сам понимает gRPC |
| Отладка curl | почти нет, нужен grpcurl | трудно: только бинарный формат | да: JSON, читаемые статусы, живые пути |
| GET и HTTP-кеш | нет | нет | да, для методов без побочных эффектов |

**Вопрос:** Почему браузерный JavaScript не может вызвать обычный gRPC-сервер напрямую?

- Браузеры не поддерживают протокол HTTP/2
- ✅ Fetch API не даёт коду читать trailer-заголовки, где gRPC хранит итоговый статус
- CORS запрещает запросы с бинарным телом
- protobuf невозможно декодировать в браузере

HTTP/2 браузеры прекрасно поддерживают, protobuf декодируется без проблем (для этого есть runtime вроде Protobuf-ES). Слабое звено — трейлеры: grpc-status доезжает именно в них, а Fetch API их коду не отдаёт. Без статуса вызова RPC в браузере не работает.

### Решение Connect: один обработчик на net/http

Вот здесь и появляется обещание фреймворка: один сгенерированный обработчик обслуживает все три протокола — gRPC, gRPC-Web и Connect — различая их по заголовку Content-Type. Не три сервера на трёх портах и не прокси в придачу: один http.Handler в вашем mux. Под капотом Connect — только Protocol Buffers и стандартная библиотека Go: никакой собственной реализации HTTP, никакого нового API балансировки и разрешения имён. В README это звучит так: всё, что вы знаете о net/http, остаётся верным, и любой пакет, работающий с http.Server, http.Client или http.Handler, работает и с Connect. Практическое следствие сложно переоценить: ваши middleware, трейсинг, метрики, httptest-тесты, настройки таймаутов и graceful shutdown — всё стандартное — подключаются к Connect-сервису без адаптеров. Контракт по-прежнему живёт в .proto-файле, код генерируется компилятором, типы проверяются на сборке — вся gRPC-эргономика сохранена, сменился только транспортный слой. Именно поэтому переезд с gRPC на Connect часто оказывается меньшей операцией, чем кажется по названию курса.

### Контракт: тот же protobuf, что и в gRPC

```go
syntax = "proto3";

package notes.v1;

option go_package = "example.com/notes/gen/notes/v1;notesv1";

message Note {
  string id = 1;
  string title = 2;
  string body = 3;
}

message GetNoteRequest {
  string id = 1;
}

message CreateNoteRequest {
  string title = 1;
  string body = 2;
}

service NoteService {
  rpc GetNote (GetNoteRequest) returns (Note);
  rpc CreateNote (CreateNoteRequest) returns (Note);
}
```

Анатомия знакома каждому, кто видел gRPC: syntax, package, go_package, messages с пронумерованными полями, service с rpc-методами. Никаких connect-специфичных аннотаций, никаких новых ключевых слов. Этот файл — обычный protobuf: его можно скормить protoc-gen-go и генератору gRPC, а можно — плагину Connect. Схема не знает, какой фреймворк её переведёт в код.

### Тот же protobuf, другой транспорт-слой

Проще всего понять Connect через сравнение с тем, что вы уже знаете. Если вы проходили курс по gRPC, вы собирали сервер так: net.Listen открывает TCP-порт, grpc.NewServer создаёт сервер, RegisterOrderServiceServer привязывает реализацию к сервису, Serve блокируется в цикле приёма — весь этот разбор в уроке про [первый gRPC-сервер](/courses/grpc-go/lessons/04-server/). В Connect эти слои меняются: вместо специализированного транспорта — обычный http.Handler, который монтируется в стандартный ServeMux и слушается вашим http.Server. Что при этом остаётся нетронутым: сами .proto-файлы, плагин protoc-gen-go (message-типы ни при чём — это про сериализацию), бинарный формат protobuf на проводе, модель кодов ошибок gRPC и весь словарь видов вызовов. Стриминг тоже на месте: если в курсе gRPC вы писали серверный стриминг WatchOrders — один запрос, поток событий — то в Connect то же самое выражается тем же словом stream в схеме; соответствующий разбор — в уроке про [серверный стриминг](/courses/grpc-go/lessons/07-server-streaming/) курса gRPC. Формула короткая: тот же protobuf, другой транспорт-слой. Логика приложения, если она не вросла в grpc.Server, переезжает почти без изменений.

### Сервер: обычный net/http, никаких grpc.NewServer

```go
package main

import (
        "context"
        "log"
        "net/http"

        "connectrpc.com/connect"
        notesv1 "example.com/notes/gen/notes/v1"
        notesv1connect "example.com/notes/gen/notes/v1/notesv1connect"
)

// Реализация сервиса: та же структура, что и у gRPC-сервера.
type notesServer struct {
        // Встроенный тип отвечает за совместимость при росте схемы.
        notesv1connect.UnimplementedNoteServiceHandler
}

func (s *notesServer) GetNote(ctx context.Context, req *notesv1.GetNoteRequest) (*notesv1.Note, error) {
        // Здесь будет поиск в базе, пока возвращаем заглушку.
        return &notesv1.Note{Id: req.Id, Title: "Первая заметка"}, nil
}

func main() {
        mux := http.NewServeMux()
        // Конструктор возвращает путь ("/notes.v1.NoteService/")
        // и http.Handler, который понимает все три протокола.
        path, handler := notesv1connect.NewNoteServiceHandler(&notesServer{})
        mux.Handle(path, handler)

        log.Fatal(http.ListenAndServe("localhost:8080", mux))
}
```

Смотрите на main: http.NewServeMux, монтирование handler-а, ListenAndServe — это обычный net/http, который вы пишете с первого дня в Go. grpc.NewServer и net.Listen отсюда исчезли, их заменил стандартный mux. Единственная connect-специфика — импорт connectrpc.com/connect и сгенерированный пакет notesv1connect с суффиксом connect: его создаёт плагин protoc-gen-connect-go, о нём ниже. Полный разбор этого файла с клиентом — в третьем уроке курса, пока важно запомнить форму: сгенерированный handler монтируется как обычный HTTP-роут.

### Браузерный клиент вызвал GetNote с Content-Type: application/json. Что вернёт сервер?

```go
func (s *notesServer) GetNote(ctx context.Context, req *notesv1.GetNoteRequest) (*notesv1.Note, error) {
        // Заметки с таким id нет — возвращаем не ошибку Go, а код RPC.
        return nil, connect.NewError(connect.CodeNotFound, errors.New("заметка не найдена"))
}
```

**Что выведет программа?**

- ✅ HTTP 404 и JSON-тело с полем code: "not_found"
- HTTP 200, а код ошибки приедет в trailer-заголовках
- HTTP 500 и пустое тело ответа
- HTTP 503 и текстовое сообщение об ошибке

Connect-протокол не использует трейлеры вообще: итог вызова известен из обычного HTTP-статуса. not_found отображается в 404 Not Found, а детали едут JSON-телом — поэтому ошибка читается даже в devtools без специальных инструментов. Полная таблица соответствия кодов — ниже в уроке.

### Три протокола одним обработчиком

Как же один handler различает трёх клиентов? По Content-Type, и правило выбора простое. Заголовки application/proto или application/json — это собственный протокол Connect: тело запроса и ответа без обёрток, осмысленные HTTP-статусы. Заголовок application/grpc (+ суффикс кодека) — классический gRPC: он приезжает на HTTP/2, и handler обслуживает его по спецификации gRPC, включая trailers и стриминг. Заголовок application/grpc-web+proto — gRPC-Web, тот самый протокол для браузеров с закодированными в тело трейлерами; Connect подаёт его нативно, без Envoy. Последний пункт стоит проговорить отдельно, потому что это прямое сравнение из FAQ проекта: серверы, построенные на Connect-Go, понимают gRPC-Web сами, а большинство реализаций gRPC от Google — нет, им нужен прокси. Практический итог для команды: старые gRPC-клиенты продолжают работать без перекомпиляции схем, фронтенд ходит JSON-ом из браузера, новый Go-клиент выбирает Connect-протокол — и всё это на одном порту, в одном деплое, под одним балансировщиком. Health-проверки и server reflection в Go-версии доступны отдельными пакетами, они тоже совместимы с gRPC.

### Вызов curl: никакого специального клиента

```go
curl \
    --header "Content-Type: application/json" \
    --data '{"sentence": "I feel happy."}' \
    https://demo.connectrpc.com/connectrpc.eliza.v1.ElizaService/Say
```

Это официальный живой демо-сервер проекта, можете выполнить команду прямо сейчас — ответ вернётся обычным JSON с HTTP 200. Путь собирается из схемы: /package.Service/Method, то есть /connectrpc.eliza.v1.ElizaService/Say. Свои сервисы дёргаются точно так же — на локальном сервере замените адрес на localhost. Для сравнения: чистый gRPC так не умеет, для ручных вызовов там нужен grpcurl и включённый reflection. Латинская буква в URL, русские комментарии в коде — смешение нормально: контракты интернациональны.

**Вопрос:** На ваш Connect-сервер пришёл запрос с Content-Type: application/grpc от старого gRPC-клиента. Что произойдёт?

- Сервер вернёт 400: тип не поддерживается
- ✅ Handler распознает классический gRPC и обслужит вызов по спецификации gRPC
- Сервер вернёт 501: gRPC требует отдельного прокси
- Запрос будет обрабатываться, только если включён Envoy

Три протокола поддерживаются handler-ом из коробки: application/grpc — это классический gRPC на HTTP/2, и сгенерированный handler общается с ним без прокси, Envoy и перекомпиляции схем. Именно поэтому миграция на Connect не требует большого взрыва.

### Connect-протокол: HTTP-статусы вместо трейлеров

Собственный протокол Connect задуман по трём правилам, которые авторы выписали в спецификации: быть читаемым обычными HTTP-инструментами, оставаться концептуально близким к gRPC и зависеть только от широко поддерживаемых фич HTTP. Для unary-вызовов результат похож на урезанный REST: POST на путь, выведенный из схемы (/notes.v1.NoteService/GetNote), тело — валидный protobuf или JSON без бинарной обёртки, а HTTP-статус ответа несёт смысл. Для методов без побочных эффектов схему помечают опцией idempotency_level = NO_SIDE_EFFECTS — и клиент отправляет обычный GET, который кешируется стандартной HTTP-инфраструктурой; gRPC такого подарка не делает. Стриминговые вызовы устроены чуть сложнее: Content-Type меняется на application/connect+json или application/connect+proto, каждое сообщение оборачивается несколькими байтами фрейминга, HTTP-статус всегда 200, а ошибка приходит в конце тела — по механике это ближе к gRPC-Web, только трейлеров нет и на HTTP/1.1 всё живёт. Исключение одно: двунаправленный стриминг требует HTTP/2, это ограничение протокола, а не библиотеки.

### Коды ошибок RPC и их HTTP-статусы

| Код | HTTP-статус | Типовой смысл |
| --- | --- | --- |
| invalid_argument | 400 Bad Request | запрос некорректен независимо от состояния системы |
| unauthenticated | 401 Unauthorized | нет валидных учётных данных |
| permission_denied | 403 Forbidden | данные есть, доступа нет |
| not_found | 404 Not Found | запрошенный ресурс не существует |
| already_exists | 409 Conflict | создание ресурса, который уже есть |
| resource_exhausted | 429 Too Many Requests | исчерпан лимит или квота |
| unavailable | 503 Service Unavailable | временная недоступность, стоит ретраить |
| unimplemented | 501 Not Implemented | метод не реализован или не включён |
| deadline_exceeded | 504 Gateway Timeout | дедлайн истёк до завершения вызова |

### К Connect-серверу подключили чистый grpc-go клиент (тот же .proto). Чем закончится вызов GetNote?

```go
// Клиент сгенерирован grpc-go по той же схеме notes.v1,
// без изменения .proto и без настроек прокси.
conn, err := grpc.NewClient("localhost:8080",
        grpc.WithTransportCredentials(insecure.NewCredentials()))
// ...
client := pb.NewNoteServiceClient(conn)
note, err := client.GetNote(ctx, &pb.GetNoteRequest{Id: "1"})
```

**Что выведет программа?**

- Ошибкой протокола: protobuf у фреймворков несовместим
- Ничего не выйдет: gRPC-клиенту нужен Envoy перед Connect-сервером
- ✅ Вызов отработает как обычно: handler сам поймёт Content-Type application/grpc
- Работает только со схемой, пересобранной плагином Connect

Это и есть обещание «три протокола одним обработчиком»: grpc-go клиент шлёт Content-Type application/grpc, и сгенерированный handler обслуживает его по спецификации gRPC, включая trailers и стриминг. Схему менять не нужно, protobuf на проводе один и тот же — совместимость обратная и прямая.

> **Браузерные стриминги: читайте мелкий шрифт.** Из браузера серверный стриминг работает нормально, а вот клиентский и двунаправленный — ограничены возможностями Fetch API: браузеры не дают полноценного отправляющего потока. Команда Connect честно фиксирует это в документации, а её TypeScript-библиотека превращает клиентский стриминг в half-duplex. Планируете чат или загрузку файлов частями из браузера — закладывайте дизайн под это ограничение заранее.

### protoc-gen-connect-go и buf: proto-first кодогенерация

Connect сохраняет главную дисциплину gRPC — proto-first: первична схема, код не пишется руками. Генерация двухступенчатая. Первый плагин — знакомый protoc-gen-go: он создаёт notes.pb.go с message-типами, и это ровно тот же файл, что и в gRPC-проекте. Второй — protoc-gen-connect-go: он создаёт notes.connect.go, где лежат интерфейс NoteServiceHandler с методом Unimplemented-заглушкой, конструктор NewNoteServiceHandler и типизированный клиент NewNoteServiceClient. Имя пакета получает суффикс connect — notesv1connect, — и по нему легко ориентироваться в импортах. Порядок установки такой: go get connectrpc.com/connect в проект, два плагина локально — и protoc с двумя --_out флагами. Но существует и современный путь: buf от компании-автора Connect заменяет хороводы protoc-флагов одним файлом buf.gen.yaml, добавляет линт схем, проверку breaking changes и реестр схем BSR. Это отдельная история, которой мы займёмся в следующем уроке про установку — там соберём notes.v1 из этого урока в рабочий код.

Восстановите ядро Connect-сервера: создание mux, монтирование сгенерированного handler-а и запуск стандартного HTTP-сервера.

```go
func main() {
        mux := http.___()
        path, handler := notesv1connect.___(&notesServer{})
        mux.Handle(path, handler)

        log.Fatal(http.___("localhost:8080", mux))
}
```

Подсказка: Всё из стандартной библиотеки net/http, кроме конструктора: mux создаёт NewServeMux, handler — сгенерированный NewNoteServiceHandler, а слушать порт начинает ListenAndServe.

Правильные ответы в пропусках: `NewServeMux`, `NewNoteServiceHandler`, `ListenAndServe`

**Вопрос:** Какой плагин генерирует файл notes.connect.go с handler-ами и клиентом?

- protoc-gen-go
- ✅ protoc-gen-connect-go
- protoc-gen-grpc-web
- buf-build-go

protoc-gen-go создаёт message-типы (notes.pb.go), а protoc-gen-connect-go — connect-специфичный код: интерфейс NoteServiceHandler, конструктор NewNoteServiceHandler и типизированный клиент. Пакет при этом получает суффикс connect: notesv1connect.

Соберите по порядку путь от .proto-схемы до первого запроса curl к Connect-сервису.

Правильный порядок строк:

1. `Пишем схему notes/v1/notes.proto с сервисом NoteService`
2. `protoc-gen-go генерирует message-типы в notes.pb.go`
3. `protoc-gen-connect-go генерирует handler и клиент в notes.connect.go`
4. `Пишем реализацию NoteServiceHandler с методом GetNote`
5. `NewNoteServiceHandler возвращает путь и http.Handler`
6. `mux.Handle монтирует handler в обычный http.ServeMux`
7. `http.ListenAndServe начинает слушать порт 8080`
8. `curl POST с Content-Type: application/json вызывает метод и получает JSON`

### Где Connect уместен, а где лишний

Мой расклад по сценариям. Первый и самый убедительный: у вас Go-бэкенд и фронтенд в браузере — Connect убирает весь слой костылей: ни REST-фасада, который отстаёт от контракта, ни Envoy, ни второй схемы. Второй: существующий gRPC-продукт, у которого появился браузерный клиент — переезд наименьшей крови, потому что gRPC-протокол поддерживается handler-ом и старые клиенты даже не заметят смены. Третий: публичные API, где хочется типизацию protobuf, но и curl-отладку жалко — JSON по умолчанию закрывает обе потребности. Четвёртый — новый проект с TypeScript-клиентом: для меня Connect стал выбором по умолчанию, а не экспериментом. Когда он лишний? Если у вас чисто внутренние gRPC-системы, где всё уже работает: Envoy стоит, браузера нет, миграция ради миграции не окупается. Если главное требование — REST-совместимость для чужих интеграций, честнее взять REST или grpc-gateway, чем протокол, который лишь похож на REST. И если команда на два месяца, а сервис один — возможно, хватит и обычного JSON API. Connect силён там, где сходятся protobuf, браузер и желание жить на net/http.

> **Как проходить этот курс.** Код уроков — настоящий Go с protobuf-кодогенерацией: сетевой код и protoc браузерная песочница сайта исполнить не может, поэтому runner-блоков в курсе нет — для практики нужен локальный Go и инструменты, установку которых разберём в следующем уроке. Интерактивы (тесты, «предскажи вывод», сборка по строкам, карточки) работают прямо на странице и дают XP, а код с построчными разборами можно копировать в свой проект.

### Карточки: словарь Connect

- **Connect** — Тонкая библиотека от Buf для gRPC-совместимых HTTP API: proto-first, кодогенерация, handler и клиент говорят на трёх протоколах — Connect, gRPC, gRPC-Web. Открыта в 2022, Apache 2.0.
- **Connect-протокол** — Собственный протокол библиотеки: обычный HTTP/1.1 или HTTP/2, без трейлеров, осмысленные HTTP-статусы, unary похож на упрощённый REST, JSON из коробки.
- **gRPC-Web** — Протокол для браузеров, где трейлеры закодированы в конец тела. Чистые gRPC-серверы требуют для него прокси (Envoy); Connect поддерживает его нативно.
- **Трейлер (HTTP)** — Заголовок, отправляемый после тела ответа. gRPC кладёт туда итоговый статус (grpc-status), а браузеры трейлеры коду не отдают — отсюда вся проблема.
- **protoc-gen-connect-go** — Плагин кодогенерации: создаёт notes.connect.go — интерфейс NoteServiceHandler, конструктор NewNoteServiceHandler и типизированный клиент. Message-типы по-прежнему делает protoc-gen-go.
- **buf** — Тулчейн от компании-автора Connect: buf.gen.yaml заменяет protoc-скрипты, плюс линт схем, проверка breaking changes и реестр схем BSR. Его ставим в следующем уроке.

### Что дальше по курсу

Следующий урок — «Установка и настройка» (02-ustanovka): go get connectrpc.com/connect, плагины protoc-gen-go и protoc-gen-connect-go, первый buf.gen.yaml. Схему notes.v1 из этого урока мы доведём до генерируемого кода, и дальше по курсу она будет расти вместе с нами: третий урок соберёт первый Connect-сервис целиком, четвёртый разберёт протоколы на проводе, шестой — ошибки и connect.NewError, седьмой — interceptors, девятый — браузерных клиентов на TypeScript. Программа всех двадцати пяти уроков, от установки до итогового проекта, живёт на [странице курса](/courses/connect/). Если protobuf для вас в новинку — начните с курса по gRPC: там протокол сериализации разобран глубже, чем это нужно для Connect.

## Коротко: что запомнить

- Connect от Buf — библиотека для gRPC-совместимых HTTP API: та же .proto-схема и protobuf, но транспорт — обычный net/http.
- Причина появления: браузер не умеет gRPC — Fetch API не отдаёт трейлеры, где живёт итоговый статус grpc-status.
- gRPC-Web решает проблему трейлеров, но требует прокси (Envoy) и оставляет только бинарный формат.
- Один сгенерированный handler на net/http обслуживает три протокола: Connect, gRPC, gRPC-Web — по Content-Type.
- Connect-протокол: POST/GET по пути /package.Service/Method, JSON или protobuf, осмысленные HTTP-статусы, not_found → 404.
- Стриминг поддержан; из браузера полноценно работает серверный, клиентский и bidi ограничены Fetch API.
- Миграция с gRPC мягкая: старые клиенты работают, схема не меняется, меняется плагин генерации.

## Домашнее задание

Возьмите любой сервис из курса по gRPC и выпишите в две колонки: что переедет в Connect без изменений (схема, message-типы, коды ошибок, стриминг в схеме) и что придётся переделать (плагин генерации, регистрация сервера, транспорт). Затем выполните curl-команду из урока на живой демо-странице connectrpc.com и убедитесь, что RPC бывает читаемым без специальных клиентов.

## Вопросы и ответы по уроку

### Что такое Connect RPC простыми словами?

Библиотека RPC от Buf: контракт в protobuf, сгенерированные типизированные клиенты, а на сервере — обычный HTTP-handler на net/http, который понимает gRPC, gRPC-Web и собственный протокол Connect одновременно.

### Connect заменяет gRPC?

Не заменяет, а обнимает: та же схема, те же коды ошибок и стриминг, плюс протокол, который работает в браузере и читается curl-ом. Существующие gRPC-клиенты продолжают работать без изменений.

### Чем Connect отличается от gRPC-Web?

gRPC-Web — только браузерный протокол с бинарным форматом, которому чистому gRPC-серверу нужен прокси. Connect — и протокол, и библиотека: без прокси, с JSON по умолчанию, и при этом полноценная совместимость с gRPC.
