<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>gRPC</title>
    <description>gRPC — это способ, как разные программы могут быстро и удобно «разговаривать» друг с другом по сети. Часто используется для микросервисов и мобильных приложений, поддерживает множество языков программирования.</description>
    <link>https://tproger.ru/tag/grpc</link>
    <atom:link href="https://tproger.ru/tag/grpc/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 03 Oct 2026 16:25:12 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>gRPC</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Создаём микросервис обработки изображений на Go с gRPC</title>
      <link>https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2</link>
      <comments>https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Go разработчик]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2</guid>
      <description><![CDATA[<p>В этой статье мы рассмотрим создание микросервиса обработки изображений на golang с использованием технологии gRPC. Цель статьи - показать как может выглядеть такой сервис и что он может в себя включать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2">Создаём микросервис обработки изображений на Go с gRPC</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[gRPC]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 17 Mar 2026 05:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Вступление</b></p><p>В этой статье мы рассмотрим создание микросервиса обработки изображений на golang с использованием технологии **gRPC**. Цель статьи - показать как может выглядеть такой сервис и что он может в себя включать. В результате мы получим полностью рабочий сервис по обработке изображений, который принимает данные, сохраняет исходную картинку,сжимает её, накладывает на неё ватермарку, изменяет размер изображения, и конвертирует его в нужный формат.</p><p>Разберём возможные варианты взаимодействия клиента с сервером для обработки больших объектов, в нашем случае это картинки:</p><p><b>1. HTTP/1.1 (REST)</b></p><p>Передача изображений в виде текстовых чанков (например, base64) приводит к значительным накладным расходам: бинарные данные увеличиваются на ~33% при кодировании в Base64, а текстовый формат неэффективен для больших объёмов.</p><p><b>2. WebSocket</b></p><p>Подходит для долгоживущих сессий и двустороннего обмена, но избыточен, если нам нужно просто «принять изображение → обработать → вернуть результат». Удержание тысяч соединений ради однократных операций — неоптимально.</p><p><b>3. gRPC</b> использует:</p><p><b>Protocol Buffers</b> — строго типизированный, компактный бинарный формат,</p><p><b>HTTP/2</b> — мультиплексирование, потоки, сжатие заголовков,</p><p><b>Client-Streaming</b> — идеально подходит для передачи одного большого файла (например, изображения) в одном вызове.</p><p><b>I. Постановка задачи</b></p><p><b>Сервис должен:</b></p><p>Принимать изображение и параметры (format, compress, watermark, width[], height[]),</p><p>Сохранять оригинал с уникальным путём (./download/YYYY/MM/DD/UUID/img/...),</p><p>Накладывать водяной знак,</p><p>Генерировать версии заданных размеров,</p><p>Сохранять полученные изображения,</p><p>Возвращать список путей.</p><p>Пример:</p><p>Запрос с width = [1920, 1280], height = [1080, 720], format = "webp", watermark = "logo.png"</p><p>→ Сервис вернёт два пути:</p><p>./download/2026/02/08/abc123/img/abc123_1920x1080.webp</p><p>./download/2026/02/08/abc124/img/abc124_1280x720.webp</p><p><b>II. Архитектура приложения</b></p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/af4f6a18-dac9-4728-bbb3-decfe99bc1c5.webp" alt="" /></figure><p><b>Обработка происходит в строгом порядке:</b></p><p>1.Приём → 2. Сохранение исходного файла→ 3. Сжатие → 4. Watermark → 5. Resize → 6. Конвертация → 7. Ответ.</p><p><b>Структура хранения:</b></p><p>./download/2026/02/08/a1b2c3d4-.../img/</p><p>├── a1b2c3d4-....jpg          ← оригинал</p><p>├── a1b2c3d4-..._800x600.png</p><p>└── a1b2c3d4-..._1024x768.png</p><p><b>Необходимые инструменты:</b></p><p>Для работы с WebP мы используем библиотеку <a href="https://pkg.go.dev/golang.org/x/image/webp" rel="nofollow">golang.org/x/image/webp</a> , а исходные утилиты можно скачать на <a href="https://developers.google.com/speed/webp/download?hl=ru" rel="nofollow">официальной странице Google</a>.</p><p>Для генерации protobuff нам нужен  <b>protoc-gen-go</b></p><p><b>protoc-gen-go-grpc</b></p><p>Позволяет генерировать определения сервисов Go для буфера протокола, заданного нашим .proto файлом <a href="https://github.com/grpc/grpc-go/releases" rel="nofollow">protoc-gen-go-grpc</a></p><p>Также для работы webp нам потребуется работа с CGO, которую мы рассмотрим отдельно.</p><p><b> III. Реализация proto файла</b></p><p>Для начала работы опишем наш proto файл. Это будет сервис с единственным rpc который будет обрабатывать картинки пользователей.</p><p>./proto/image.proto</p><p>Мы используем Client-Streaming RPC — клиент может отправить несколько сообщений, сервер — один ответ. Этот способ поможет нам в случае необходимости гибкого расширения и избежания ограничений на размер одного сообщения.</p><p><b>V. Реализация основных функций</b></p><p><b>1. Создание сервера</b></p><p><b>1.1 Генерация  go файлов из .proto:</b>  Сгенерируем файлы для реализации сервера с помощью protoc:</p><p>У нас должно получиться 2 файла image.pb.go и image_grpc.pb.go в директории proto</p><p><b>1.2 Реализуем конструктор сервера и interceptor</b> (аналог middleware в grpc) восстановления после паники:</p><p>./internal/app/server.go</p><p>Теперь реализуем функцию запуска нашего grpc сервера:</p><p>Мы создали наш grpc сервер, но пока нет никакой реализации ImageServiceServer который сгенерировал нам protoc, это просто интерфейс который нам и нужно реализовать.</p><p><b>2. Реализация ImageServiceServer</b></p><p>Нам необходимо создать структуру ImageServer которая реализует интерфейс ImageServiceServer с его методом DownloadImage, также создадим конструктор для него :</p><p>./internal/app/image.go</p><p>Нам осталось реализовать ключевые функции для нашего сервиса, а именно: saveSourceFiles: отвечает за сохранение исходных файлов и их сжатие, watermark: наложение ватермарки , resizeAndSave: изменения размера картинки и его конвертация в нужный формат изображения.</p><p><b>3. Сохранение оригинала</b></p><p>Мы создаем путь для сохранения картинки, сохраняем её с необходимым для клиента уровнем сжатия и потом для удобства всю метаинформацию об картинке помещаем уже в нашу структуру и работаем в дальнейшем только с ней:</p><p>./internal/app/save.go</p><p>Для ускорения нашего процесса обработки все этапы мы будем выполнять конкурентно с помощью горутин.</p><p><b>4. Водяной знак </b></p><p>Следующим этапом идёт наложение водяного знака на нашу картинку. Процесс наложения: мы передаем каждой горутине по изображению, они его обрабатывают, а для того чтобы убедиться что они все обработались мы применяем sync.WaitGroup. Сам процесс наложения водяного знака это задание параметров для установки его на исходную картинку, в нашем случае мы делаем её полупрозрачную с небольшим углом поворота и в случайном месте и сохраняем её:</p><p>./internal/app/watermark.go</p><p>Остаётся только изменить размер и сохранить в нужном формате наши обработанные изображения.</p><p><b>5. Resize и конвертация.</b></p><p>Теперь создадим файл resize.go и реализуем функцию изменения размера изображении и сохранения в нужном нам формате:</p><p>./internal/app/resize.go</p><p>Теперь реализуем main.go в котором создадим и вызовем наш сервис обработки изображений.</p><p>./internal/cmd/main.go</p><p><b>VI. CGO</b></p><p>Наше приложение полностью готово, но теперь нужно удостовериться, что у нас работает поддержка CGO. Для начала нужно убедиться что мы скачали и установили webp по ссылке [официальная страница Google](https://developers.google.com/speed/webp/download?hl=ru). Далее нам необходимо установить GCC, без него go не может распознать импортированные C файлы, скачиваем и устанавливаем [официальные зеркала GNU](https://gcc.gnu.org/mirrors.html). Теперь нужно проверить, что переменная CGO_ENABLED=1, для этого используем команду go env и проверяем, если она равна 0, то используем go set  CGO_ENABLED=1 и проверяем ,что она применилась, если нет то перезагружаем нашу систему и проверяем. Теперь мы готовы собрать наше приложение и приступить к тестированию.</p><p><b>VII. Тестирование и оптимизация</b></p><p><b>Тестирование с Bruno</b></p><p>Здесь вы можете тестировать удобными для вас средствами такими как Postman, Bruno, Yaak, grpccurl и т.д., главное чтобы они поддерживали тестирование grpc методов. Рассмотрим пример с Bruno:</p><p>1.Конвертируйте изображение в Base64: Image to Base64 Converter</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/3b10f151-2654-42b1-b6a2-1e6805d79ba2.webp" alt="" /></figure><p>2.Откройте Bruno создайте новый grpc запрос</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/94dba9c1-7930-43f5-accf-1753036005db.webp" alt="" /></figure><p>3. Выбираем метод grpc:</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/b614edcd-171f-49e5-8ba2-cd4b73283551.webp" alt="" /></figure><p>4.Уберите ползунок с reflection и укажите .proto файл</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/8a88b632-4d1a-41a0-9818-0822a6613551.webp" alt="" /></figure><p>5.Выберите метод DownloadImage</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/2a0f8f65-cb62-4442-a867-10d3c69f145d.webp" alt="" /></figure><p>6.В поле message заполните поле в соответствии с параметрами, например:</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/8f454490-7182-4641-8a31-f56fe6236546.webp" alt="" /><figcaption>если появляются проблемы при подключении к сервису, то не выносите текстовое представление картинки в переменную</figcaption></figure><p>В поле image нужно скопировать текстовую строку ,что идёт после запятой, сгенерированную на шаге 1</p><p>7.Далее нужно запустить наше приложение и подключиться к нему с помощью кнопки →</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/4a166e9e-22d3-4369-be1e-b68534623765.webp" alt="" /></figure><p>В случае успеха должен появиться статус streaming</p><p>8.Отправляем наше сообщение/сообщения нажав на кнопку "Send message" один или несколько раз и завершаем нашу передачу сообщений с помощью кнопки → (если не нажать то приложение будет ожидать приёма сообщений). Результатом будет возврат путей наших обработанных сообщений</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/7e269ec1-2cec-4926-8ccc-a9de76d3e9ff.webp" alt="" /></figure><p><b>VIII. Заключение</b></p><p>Подведем итоги, мы создали сервис который:</p><p>Использует gRPC для эффективной передачи данных,</p><p>Поддерживает WebP, JPEG, PNG,</p><p>Безопасен в конкурентной среде,</p><p>Можно легко масштабировать.</p><p>В результате получился сервис обработки изображений. Этот подход применим не только к изображениям, но и к любым бинарным данным.</p><p>Исходный код доступен по <a href="https://github.com/art9276/image-converter" rel="nofollow">ссылке</a></p><p><b>Спасибо за внимание!</b></p>]]></content:encoded>
    </item>
    <item>
      <title>Генерируем CRUD для gRPC по схеме БД следуя Google AIP</title>
      <link>https://tproger.ru/articles/generiruem-crud-dlya-grpc-po-sheme-bd</link>
      <comments>https://tproger.ru/articles/generiruem-crud-dlya-grpc-po-sheme-bd?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Артем Украинский]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/generiruem-crud-dlya-grpc-po-sheme-bd</guid>
      <description><![CDATA[<p>Как с помощью db-exporter автоматизировать процесс генерации CRUD-операций для gRPC, соблюдая стандарт Google AIP</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/generiruem-crud-dlya-grpc-po-sheme-bd">Генерируем CRUD для gRPC по схеме БД следуя Google AIP</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[gRPC]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 20 Nov 2025 10:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>К сожалению, жизнь разработчика не всегда полна сложными и интересными задачами, время от времени мы все-таки пишем CRUD'ы.</p><p>Задача в целом проста:</p><ol><li>Открыть структуру таблицы</li><li>Скопировать названия колонок</li><li>Соотнести типы, которые существуют в спецификации (gRPC, OpenAPI, и т.п.)</li><li>Описать API метод</li><li>Проверить на соответствие стайл-гайду</li></ol><p>Но это утомительно и отнимает драгоценное время разработчиков. Данную  инструкцию за нас может выполнить инструмент <b>db-exporter. </b>В этой статье рассмотрим, как с его помощью автоматизировать процесс генерации CRUD-операций для gRPC, соблюдая <a href="https://google.aip.dev/121">стандарт</a> Google AIP по ресурсно-ориентированному дизайну.</p><p>В последующих разделах мы подробно рассмотрим:</p><ul><li>Принцип работы db-exporter</li><li>Процесс настройки и конфигурации</li><li>Примеры генерации различных типов операций</li><li>Валидацию сгенерированных proto файлов</li><li>Как внедрить инструмент для постоянной работы с ним</li></ul><h2>Знакомимся с инструментом</h2><p>db-exporter — это Open Source утилита для генерации кода и документации к схеме базы данных. «Экспортировать» можно в различные распространенные форматы: диаграмма классов, protobuf, код на Go и другие. На данный момент инструмент поддерживает PostgreSQL и MySQL. Реализована поддержка основных операционных систем. Инструмент достаточно молодой и активно развивается.</p><figure><img src="https://media.tproger.ru/user-uploads/133667/2025-10-31/fefdf04a-7291-41f2-9722-23a28266595f.png" alt="" /><figcaption>Принцип работы db-exporter</figcaption></figure><p>Для начала работы с db-exporter необходимо скачать его со страницы релизов. Далее разархивировать и переместить в /usr/local/bin. Или выполнить всё одной командой.</p><p><b>Mac OS</b></p><p><b>Linux</b></p><p>Теперь у нас установлен инструмент и мы почти готовы его запускать, но перед этим разберемся, составим пример таблицы, над которой будем проводить эксперименты.</p><h2>Составим пример</h2><p>Договоримся, что нашим примером для генерации кода будет являться таблица пользователей. У пользователей есть: id, имя, отчество, дата создания, статус (активен, заблокирован) и дата удаления.</p><p>Итого, схема выглядит так:</p><p>Данного примера достаточно для того, чтобы рассмотреть ключевые моменты:</p><ul><li>Генерация первичных ключей (поле id)</li><li>Генерация опциональных полей (поле middle_name)</li><li>Генерация временных меток (поля created_at, deleted_at)</li><li>Генерация енамов (поле status, енам user_status)</li><li>Работа с soft-delete</li></ul><h2>Генерируем protobuf</h2><p>Для того, чтобы запустить db-exporter необходимо описать конфигурацию —делается это декларативно, в yaml-файле. db-exporter оперируют задачами, в которых описаны:</p><ul><li>Формат, в котором нужно выполнить генерацию. В нашем случае — это grpc-crud<br /></li></ul><ul><li>Директория, в которую сохранить файлы</li><li>Специфичные формату параметры (далее: спека задачи)</li></ul><p>Также важно не забыть указать подключение к базе данных. В нашем примере, используется PostgreSQL на 5432 порту. Для успешного запуска стоит убедиться, что БД запущена и в ней есть схема с таблицами.</p><p>Итого, конфигурация, описывающая перечисленные требования, выглядит следующим образом:</p><p>Сохраняем этот файл, как .db-exporter.yaml.</p><p>Далее запускаем инструмент, выполняя команду db-exporter и получаем отчет о проделанной работе — db-exporter сообщает о том, какие файлы были созданы и какой они имеют вес.</p><figure><img src="https://media.tproger.ru/user-uploads/133667/2025-11-10/8ccb11d3-2595-4782-95ef-d920d8f76a0c.png" alt="" /><figcaption>Результат выполнения db-exporter</figcaption></figure><h3>Разбираемся, что получили на выходе</h3><p>В результате выполнения команды был сгенерирован файл users.proto, в котором используется синтаксис соответствует proto3. Файл содержит:</p><ul><li><b>UsersService</b> с методами <i>List</i>, <i>Get</i>, <i>Delete</i>, <i>Undelete</i>, <i>Create</i>, <i>Patch</i></li><li>Сообщение <b>User</b>, отражающее таблицу users</li><li>Енам <b>UserStatus</b></li></ul><h4>Сообщение User и enum UserStatus</h4><p>Сообщение User отражает структуру таблицы users и имеет вид:</p><p>Что здесь видим?</p><ol><li>id<i> </i>- uuid'ы генерируются, как строки. Первичный ключ помечается, как OUTPUT_ONLY, говоря о том, что поле используется только для ответов.</li><li>name, email сгенерированы, как строки</li><li>Поля created_at, deleted_at обернуто в гугловый Timestamp<i><br /></i></li><li>Для статуса пользователя сгенерирован енам UserStatus</li></ol><p>UserStatus выглядит следующим образом</p><h4>Метод для получения списка пользователя</h4><p>Метод List принимает на вход ListUsersRequest и возвращает ListUsersResponse</p><p>Запрос включает в себя поле с массивом идентификаторов пользователей. db-exporter добавляет в тело запроса первичный ключ, если первичный ключ состоит из одного поля. Также в запросе присутствует флаг <i>show_deleted</i>, как того требует стандарт <a href="https://google.aip.dev/132">AIP-132</a>, при работе с сущностями, поддерживающими soft-delete: по умолчанию сервер возвращает список активных пользователей, например, используя sql-запрос с фильтром deleted_at is null.</p><p>По умолчанию db-exporter добавляет token-based пагинацию, описанную в <a href="https://google.aip.dev/158">AIP-158</a>. Такая пагинация удобна для межсервисного взаимодействия. Но если основной клиент вашего API — это фронтенд, то вероятнее всего, вам нужна офсетная пагинация. Ее можно включить, добавив в спеку задачи pagination: offset. Если пагинация уж совсем не требуется, то pagination: none.</p><p>В ответе же список пользователей и токен следующей страницы.</p><h4>Метод получения пользователя</h4><p>Стандарт <a href="https://google.aip.dev/131">по получению ресурса</a> описывает достаточную простую конструкцию — Метод Get принимает на вход GetUserRequest и отдает на выход сообщение User.</p><p>Тело запроса включает в себя поле id, так как оно является первичным ключом.</p><h4>Методы удаления и восстановления пользователя</h4><p>Стандарт <a href="https://google.aip.dev/164">AIP-164</a> гласит: мало того, что сущность удаляется методом <b>Delete</b>, так еще нужно и мочь ее восстанавливать с помощью метода <b>Undelete</b>, если таблица поддерживает soft-delete.</p><p>Поэтому в результате генерации мы получаем методы Delete и Undelete: db-exporter самостоятельно определяет поддержку soft-delete у таблиц, смотря на поля <i>deleted_at</i> и <i>delete_time</i>.</p><p>Метод <b>Delete</b> принимает на вход DeleteUserRequest и отдает на выход DeleteUserResponse. Метод <b>Undelete </b>принимает UndeleteUserRequest и возвращает восстановленный ресурс User.</p><p>Тела запросов также, как и для метода Get, содержат поле первичного ключа — id.</p><p>По умолчанию возвращается <i>google.protobuf.Empty</i>, как требуется в стандарте<i>. </i>Возможна генерация пустого сообщения<i> DeleteUserResponse </i>— для этого нужно добавить параметр в спеку:</p><h3>Методы создания и обновления пользователя</h3><p>По стандартам <a href="https://google.aip.dev/133">AIP-133</a> и <a href="https://google.aip.dev/134">AIP-134</a> методы<b> Create</b> и <b>Update</b> имеют похожие сигнатуры.</p><p>Тела запросов также схожи, включают в себя ресурс User и возвращают его обновленную версию.</p><p>По стандарту поле update_mask предполагается использовать для частичного обновления сущности. <b>FieldMask</b> содержит в себе список полей, которые необходимо обновить у сущности User.</p><h3>Добавляем HTTP пути к методам</h3><p>В gRPC есть полезная опция <i>google.api.http</i>, с помощью которой можно указать HTTP адрес для метода. Ее полезно использовать, если вы используете REST поверх gRPC сервисов — например, с помощью grpc-gateway.</p><p>Наверняка, мы хорошие разработчики и версионируем свой API: установим версию v1 в параметре path_prefix.</p><p>И получаем вот такой результат:</p><h2>Валидируем результат</h2><p>Теперь, когда у нас есть файл users.proto — важно проверить, что он корректен синтаксически. Для этого соберем go-клиент, используя утилиту protoc.</p><h3>Указываем Go пакет</h3><p>Выше мы обсуждали gRPC контракты без привязки к конкретному стеку. Ну что ж, время пришло!</p><p>Для генерации Go-клиента в .proto файле необходимо указать опцию <b>go_package</b>. Мы можем сами поправить .proto файл, но при частом использовании db-exporter это будет не так удобно, поэтому скажем экспортеру, какой пакет нам нужен. Для этого нужно указать опцию в спеке задачи .db-exporter.yaml:</p><p>Нам остается еще раз сгенерировать users.proto, используя уже знакомую команду db-exporter.</p><h3>Собираем зависимости</h3><p>Сгенерированный users.proto импортирует зависимости <i>google.api </i>для указания HTTP методов/путей, обязательности полей. Их можно скачать с GitHub <i>googleapis</i>: <a href="https://github.com/googleapis/googleapis/blob/master/google/api/http.proto">http.proto</a>, <a href="https://raw.githubusercontent.com/googleapis/googleapis/refs/heads/master/google/api/field_behavior.proto">field_behavior.proto</a> и <a href="https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto">annotations.proto</a>.</p><p>Скачать зависимости можем следующим скриптом:</p><p>Итого мы должны были организовать следующую структуру файлов:</p><p>Теперь запустим генерацию гошного кода:</p><p>В результате выполнения команды в наш проект добавились 2 новых файла:</p><ul><li>pkg/api/users.pb.go — структуры для ресурса, запросов и ответов</li><li>pkg/api/users_grpc.pb.go — rpc-сервис UserService и клиент к нему</li></ul><p><b>Вывод</b>: из сгенерированного db-экспортером .proto файла можно сгенерировать валидный програмнный код. Считаем проверку успешно выполненной</p><h2>Непрерывная генерация</h2><h3>Перезапись файлов</h3><p>Собранная нами конфигурация отлично подходит для «одноразовых генераций», но со временем, когда сервис обрастет новыми методами, использовать генератор будет неудобно из-за того, что он по умолчанию перезаписывает уже существующие файлы. Чтобы избежать такой ситуации, необходимо указать генератору, что мы не хотим перезаписывать файлы. Сделать это можно, добавив опцию <i>skip_exists</i>.</p><p>Теперь db-exporter не будет перезаписывать уже существующие файлы и будет генерировать только новые.</p><h3>Генерация лишних таблиц</h3><p>По умолчанию db-exporter генерирует файлы по всем таблицам из схемы БД. В проекте может десяток или десятки таблиц, не для всех из них нужна генерация CRUD-операций. Генератору можно передать список таблиц, по которым необходимо генерировать файлы.</p><p>Но править постоянно конфиг не очень удобно. Укажем переменную.</p><p>Теперь мы можем запускать генерацию по конкретным таблицам, например вот так:</p><p>Или обернуть это в Makefile:</p><p>Использовать эту конструкцию можно следующим образом:</p><h2>Что в итоге?</h2><p>В итоге мы собрали рабочую конфигурацию db-exporter, которая позволяет генерировать CRUD по схеме БД в валидный .proto файл, включая полезные опции: <i>google.api.field_behavior</i> и <i>google.api.http</i>. Собранную конфигурацию и необходимое окружение вы сможете найти по <a href="https://github.com/ArtARTs36/db-exporter/tree/master/examples/grpc-crud">этой ссылке</a>.</p><p>Надеюсь, этот пост был для вас полезным и поможет ускорить разработку крудов. Если у вас есть предложения по улучшению/расширению кодо-генератора, добро пожаловать в <a href="https://github.com/ArtARTs36/db-exporter">репозиторий</a>.</p><p>В репозитории вы также сможете найти примеры генерации диаграмм классов, mermaid, markdown и так далее.</p>]]></content:encoded>
    </item>
    <item>
      <title>Post-GraphQL мир: стоит ли переходить на gRPC и tRPC</title>
      <link>https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc</link>
      <comments>https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc</guid>
      <description><![CDATA[<p>Подробное сравнение технологий API для разработчиков. Разбираем сильные и слабые стороны GraphQL, gRPC и tRPC на реальных кейсах. Практические рекомендации по выбору технологии для вашего проекта.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc">Post-GraphQL мир: стоит ли переходить на gRPC и tRPC</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Post-GraphQL]]></category>
      <category><![CDATA[gRPC]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Oct 2025 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Архитектура API постоянно меняется. Несколько лет назад GraphQL казался панацеей от всех болезней REST. Сегодня всё чаще говорят о двух других технологиях — gRPC и tRPC. Это не означает, что GraphQL уже не актуален — он нашёл свою нишу и продолжает развиваться, но это уже не универсальное решение для любых задач. Фреймворки gRPC и tRPC открывают принципиально иные подходы к построению API. Они решают конкретные проблемы в конкретных контекстах.</p><p>Узнаем, что предлагает Post-GraphQL мир, в чём плюсы и минусы фреймворков gRPC и tRPC и в каких ситуациях стоит пользоваться новыми инструментами.</p><h2>От монолитов к микросервисам: как мы здесь оказались</h2><p>Чтобы понять современный ландшафт API, вернёмся на несколько лет назад. REST доминировал десятилетиями. Этот подход прост для понимания, но имеет фундаментальные проблемы.</p><p>Типичный сценарий разработки под REST выглядел так: фронтендеры постоянно просили бэкендеров добавить новые поля в ответы API или создать новые эндпоинты. Возникала тесная связь между командами, что замедляло разработку.</p><p>GraphQL решил эти проблемы, предоставив клиентам возможность запрашивать именно те данные, которые им нужны. Один запрос вместо десятков, строгая типизация, интроспекция — всё это сделало GraphQL популярным.</p><p>Но идеальных технологий не существует. GraphQL принёс свои сложности:</p><ul><li>кэширование на клиенте стало нетривиальной задачей;</li><li>сложные запросы создавали нагрузку на сервер;</li><li>необходимость изучать новый язык запросов отпугивала разработчиков.</li></ul><p>Эволюция продолжилась. Сегодня мы видим, как экосистема разделилась на два основных направления: высокопроизводительные межсервисные коммуникации (gRPC) и бесшовную разработку полного стека на TypeScript (tRPC).</p><h2>gRPC: высокопроизводительная связность для микросервисов</h2><p>gRPC — не просто ещё один протокол, а полноценная экосистема для построения эффективных распределённых систем. Технология создана Google для внутренних нужд, где критически важны производительность и надёжность.</p><p>gRPC использует Protocol Buffers (protobuf) в качестве языка описания интерфейсов и формата сериализации. Это бинарный формат, который значительно эффективнее текстового JSON. Сообщения занимают меньше места и быстрее обрабатываются.</p><p>HTTP/2 — ещё один козырь gRPC. Этот протокол поддерживает мультиплексирование запросов, server push и двунаправленные потоки. В отличие от традиционных HTTP-запросов, gRPC может работать с постоянными соединениями и потоковой передачей данных в реальном времени.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/ca6ce939-89ec-4b24-b4e4-dbccf40845cd.png" alt="" /></figure><h2>Когда gRPC действительно сияет</h2><p>gRPC идеально подходит для микросервисных архитектур, где сервисы общаются друг с другом внутри защищенной сети. Финансовые системы, телекоммуникационные платформы, игровые серверы — везде, где важны эффективность и минимальное время отклика.</p><p>Сильная сторона gRPC — потоковая передача данных. Представьте систему мониторинга, где сервер постоянно отправляет метрики, или чат-приложение с тысячами одновременных соединений. gRPC справляется с такими задачами лучше REST или GraphQL благодаря встроенной поддержке потоков на уровне протокола HTTP/2.</p><p>В отличие от REST, который требует постоянного установления новых HTTP-соединений, gRPC поддерживает двунаправленные потоки в рамках одного соединения, что снижает накладные расходы и позволяет эффективнее использовать сетевые ресурсы.</p><p>Межъязыковое взаимодействие — ещё одно преимущество. У вас могут быть сервисы на Go, Python, Java и C++, которые легко общаются между собой благодаря сгенерированному коду из protobuf-файлов.</p><h2>Ограничения gRPC</h2><p>Браузерная поддержка требует дополнительных усилий. Нативные gRPC-клиенты в браузерах не работают, нужен прокси gRPC-Web. Это добавляет сложности в настройке.</p><p>Человекочитаемость сообщений оставляет желать лучшего. Бинарный формат protobuf неудобен для отладки без специальных инструментов. Разработчики часто используют JSON-эквиваленты для разработки, жертвуя производительностью.</p><p>gRPC требует кодогенерации. При каждом изменении API нужно обновлять protobuf-файлы и перегенерировать код для всех языков. Это добавляет лишний шаг в процесс разработки.</p><h2>tRPC: типобезопасность без схем и кодогенерации</h2><p>tRPC занимает противоположную нишу. Это технология для полного стека на TypeScript, где важны скорость разработки и типобезопасность.</p><p>Философия tRPC — минимализм. Не нужны схемы, кодогенерация, сложные настройки. Вы определяете процедуры (запросы и мутации) на TypeScript, а клиент автоматически получает информацию о типах.</p><p>tRPC использует обычный HTTP поверх HTTP/1.x, что делает его совместимым с любым браузером. Транспортный формат — JSON, который легко отлаживать с помощью стандартных инструментов разработчика.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/f029279a-d51f-4666-bb04-1f409c22b18f.jpg" alt="" /></figure><h2>Сильные стороны tRPC</h2><p>Скорость разработки — главный плюс tRPC. Изменения на сервере сразу отражаются в типах на клиенте. Не нужно ждать кодогенерации или вручную синхронизировать типы.</p><p>Идеальная интеграция с экосистемой TypeScript. Если ваш стек — Next.js, React, Prisma и TypeScript, то tRPC станет естественным выбором. Разработка напоминает работу с монолитом, но с распределённой архитектурой.</p><p>tRPC отлично работает в монорепозиториях. Один репозиторий содержит и клиент, и сервер, что упрощает синхронизацию версий и рефакторинг.</p><h2>Когда tRPC не подходит</h2><p>tRPC привязан к экосистеме TypeScript. Если у вас мультиязычная архитектура или вы планируете публичное API для клиентов на разных языках, tRPC — не лучший выбор.</p><p>Отсутствие схемы может быть ограничением. GraphQL-схема служит документацией и основой для инструментов вроде Apollo Studio. tRPC не предоставляет аналогичных возможностей для интроспекции API.</p><p>tRPC не решает проблему over-fetching на том же уровне, что GraphQL. Клиент не может точно указать, какие поля нужны в ответе — он получает всю структуру данных, определённую процедурой.</p><h2>Сравнительная таблица: gRPC vs GraphQL vs tRPC</h2><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/94988143-b27a-40e5-a33a-f84a3c5a8013.png" alt="" /></figure><h2>GraphQL рано списывать со счетов</h2><p>Несмотря на рост популярности gRPC и tRPC, GraphQL остаётся сильным игроком на рынке API. Технология развивается, появляются новые инструменты и практики:</p><ul><li><b>GraphiQL 2.0.</b> Не просто обновление, а полный редизайн официального инструмента для разработки запросов. Новая версия, разрабатываемая GraphQL Foundation, предлагает модульную архитектуру с поддержкой плагинов для расширения функциональности.</li><li><b>Apollo MCP Server.</b> Адаптация GraphQL к новейшим технологическим трендам, в частности — к интеграции с искусственным интеллектом. Apollo MCP Server позволяет подключать большие языковые модели (LLM) и AI-системы к вашим API через GraphQL, выступая для них стандартизированным и безопасным интерфейсом. Это решает такие проблемы AI, как необходимость детерминированного выполнения запросов и контроля политик доступа.</li><li><b>Автоматические постоянные запросы</b> (Automatic Persisted Queries, APQ). Клиент может отправлять на сервер не текст запроса, а его хэш. Сервер, заранее получивший полный запрос, выполняет его, найдя по хэшу. Это значительно сокращает объем передаваемых данных и ускоряет работу, особенно в мобильных сетях.</li></ul><p>GraphQL незаменим, когда у вас множество клиентов с разными требованиями к данным. Мобильное приложение, веб-интерфейс, партнерские интеграции — каждый может запросить именно те данные, которые нужны, без изменения серверной логики.</p><p>Эволюция GraphQL продолжается. Подходы вроде GraphQL Federation позволяют распределить схему между разными командами, что решает проблему монолитной схемы в больших организациях.</p><p>Инструменты вроде graphql-tada и Grats улучшают процесс разработки с GraphQL, приближая его к удобству tRPC. Они обеспечивают типобезопасность без потерь в гибкости.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/05238f17-ec27-4483-90d6-4340e984d173.png" alt="" /></figure><h2>Как выбрать: практические рекомендации</h2><p>Выбор технологии зависит от конкретного контекста. Не следуйте трендам вслепую — это приводит к архитектурным ошибкам. Вместо вопроса «Что сейчас модно?» спросите: «Какую проблему я решаю?».</p><p>Проанализируйте свой проект по нескольким ключевым параметрам. Ответы помогут принять взвешенное решение.</p><h2>Вопрос первый: какую проблему вы решаете?</h2><p>Разные технологии созданы для разных сценариев. Определите основную боль вашего проекта:</p><ul><li>Нужна высокая производительность для внутренней коммуникации микросервисов → gRPC. Бинарный протокол и HTTP/2 дают преимущество в скорости при частых вызовах между сервисами.</li><li>Хотите дать клиентам гибкость в запросах данных → GraphQL. Разные потребители API могут запрашивать только нужные поля без изменения серверной логики.</li><li>Разрабатываете full-stack приложение на TypeScript и хотите максимальной типобезопасности → tRPC. Единая типовая система от бэкенда до фронтенда ускоряет разработку и снижает количество ошибок.</li></ul><h2>Вопрос второй: какая у продукта архитектура?</h2><p>Технологический стек определяет доступные опции. Оцените текущую и планируемую инфраструктуру:</p><ul><li>Один язык программирования по всему стеку (TypeScript) → tRPC. Тесная интеграция с экосистемой TypeScript становится приоритетом.</li><li>Несколько языков (Go, Python, Java, etc.) → gRPC или GraphQL. gRPC обеспечивает эффективную коммуникацию между разнородными сервисами, а GraphQL подходит для публичного API.</li><li>Планируете масштабирование на разные платформы → GraphQL. Единая схема API работает с любым клиентом, независимо от языка или платформы.</li></ul><h2>Вопрос третий: кто потребители вашего API?</h2><p>Проанализируйте, кто будет использовать ваш API:</p><ul><li>Внутренние сервисы → gRPC. Высокая производительность и эффективность важнее человекочитаемости.</li><li>Внешние клиенты (мобильные приложения, партнеры) → GraphQL. Возможность точного запроса данных снижает нагрузку на сеть и упрощает интеграцию.</li><li>Собственный фронтенд на TypeScript → tRPC. Максимальная скорость разработки и типобезопасность окупают ограничения по браузерной поддержке.</li></ul><h2>Вопрос четвертый: каковы требования к инструментарию?</h2><p>Разработка не заканчивается на написании кода. Оцените важность сопутствующих инструментов:</p><ul><li>Важна интроспекция API и полноценная экосистема инструментов → GraphQL. Встроенная интроспекция и инструменты вроде Apollo Studio предоставляют мощные возможности для отладки и мониторинга.</li><li>Нужна максимальная производительность и минимальные накладные расходы → gRPC. Бинарный формат и HTTP/2 обеспечивают эффективную передачу данных.</li><li>Приоритет — скорость разработки и минимальная конфигурация → tRPC. Отсутствие схем и кодогенерации ускоряет итерации.</li></ul><h2>Дополнительные практические соображения</h2><p>Командная экспертиза играет важную роль. Любая новая технология требует времени на освоение. Оцените готовность команды изучать новые инструменты.</p><p>Операционные расходы — ещё один фактор. gRPC требует инфраструктуры для мониторинга бинарных протоколов. GraphQL нуждается в инструментах для анализа запросов и защиты от перегрузки.</p><p>Рассмотрите возможность гибридного подхода. Крупные проекты часто используют разные технологии для разных задач. Внутренняя коммуникация — gRPC, публичное API — GraphQL, админ-панель — tRPC.</p><p>Проведите пилотные испытания. Реальные нагрузки могут преподнести сюрпризы. Протестируйте выбранную технологию на критически важных сценариях перед полным внедрением.</p><h2>Почему гибридные подходы набирают популярность</h2><p>Современные приложения редко бывают простыми. Один продукт может включать мобильное приложение, веб-интерфейс, админ-панель и интеграции с партнерами. Каждый компонент имеет уникальные требования к API.</p><p>Монолитная архитектура API часто не справляется с разнородными нагрузками. Один протокол пытается угодить всем, но в итоге не идеален ни для кого. Гибридный подход признает это разнообразие и предлагает адресные решения.</p><p>Технологическая зрелость инструментов позволяет легко комбинировать разные подходы. Контейнеризация, сервисная сетка и API-гейтвеи упрощают интеграцию разнородных компонентов.</p><h2>Реальные сценарии комбинирования технологий</h2><p>Рассмотрим типичный пример e-commerce платформы. Система состоит из нескольких логических частей, каждая со своими требованиями.</p><p>Микросервисы инвентаризации и платежей общаются через gRPC. Здесь важна низкая задержка и эффективность сети. Бинарный протокол и HTTP/2 идеально подходят для частых внутренних вызовов.</p><p>Публичное API для мобильных приложений и партнеров использует GraphQL. Разные клиенты могут запрашивать только нужные данные без переразработки серверной логики. Это снижает нагрузку на сеть и упрощает поддержку API.</p><p>Админ-панель и внутренние инструменты построены на tRPC. Разработчики работают в единой TypeScript-экосистеме, что ускоряет итерации. Типобезопасность от backend до frontend снижает количество ошибок.</p><h2>Техническая реализация гибридной архитектуры</h2><p>Ключевой элемент гибридной системы — API-шлюз. Он маршрутизирует запросы к соответствующим бэкендам, преобразует форматы данных и обеспечивает единую точку входа.</p><p>Шлюз принимает HTTP-запросы и определяет, куда их направить. GraphQL-запросы идут к GraphQL-серверу, gRPC-вызовы — к микросервисам, а tRPC-запросы — к соответствующим процедурам.</p><p>Преобразование протоколов происходит прозрачно для клиента. Например, мобильное приложение отправляет GraphQL-запрос, который шлюз может преобразовать в gRPC-вызов к внутренним сервисам.</p><p>Сервисная сеть (service mesh) упрощает управление гибридной инфраструктурой. Она обеспечивает обнаружение сервисов, балансировку нагрузки и мониторинг независимо от используемых протоколов.</p><h2>Организационные аспекты смешанного подхода</h2><p>Гибридная архитектура влияет на структуру команд. Вместо единой бэкенд-команды появляются специализированные группы:</p><ul><li>Команда платформы отвечает за базовую инфраструктуру: API-шлюз, сервисную сеть, мониторинг. Они обеспечивают совместимость различных технологий и единые стандарты качества.</li><li>Команды продукта фокусируются на конкретных функциональных областях. Они выбирают оптимальные технологии для своих задач в рамках установленных стандартов.</li></ul><p>Такое разделение требует чётких интерфейсов между командами. Контракты API становятся критически важными — они определяют точки взаимодействия между различными частями системы.</p><h2>Проблемы и решения при внедрении</h2><p>Гибридный подход не лишён сложностей. Основная проблема — высокая операционная нагрузка. Каждая технология требует специфических знаний и инструментов мониторинга.</p><p>Единая система мониторинга обязательна. Нельзя иметь отдельные дашборды для gRPC, GraphQL и tRPC. Нужен агрегированный взгляд на всю систему, который показывает взаимосвязи между компонентами.</p><p>Стандартизация практик разработки становится критически важной. Разные команды должны следовать единым принципам документирования, версионирования и тестирования API.</p><p>Обучение разработчиков — еще один вызов. Программисты должны понимать несколько технологий, а не специализироваться на одной. Это требует инвестиций в обучение и обмен знаниями.</p><h2>Когда гибридный подход оправдан</h2><p>Переход к смешанной архитектуре требует дополнительных ресурсов. Он не всегда целесообразен для небольших проектов или стартапов на ранней стадии.</p><p>Проекты с явно выраженными разнородными требованиями к API получают максимальную выгоду. Если у вас есть и высоконагруженные внутренние сервисы, и публичное API с разнообразными клиентами — гибридный подход может быть оптимальным.</p><p>Системы, которые эволюционируют из монолита в микросервисы, часто естественным образом приходят к гибридной архитектуре. Постепенное внедрение новых технологий менее рискованно, чем полный рефакторинг.</p><p>Команды с сильной DevOps-культурой лучше справляются со сложностью гибридных систем. Автоматизация развёртывания, мониторинга и масштабирования снижает операционную нагрузку.</p><h2>Эволюция вместо революции</h2><p>Гибридный подход — не про выбор одной технологии, а про использование сильных сторон каждой. Это признание того, что современные системы слишком сложны для универсальных решений.</p><p><b>Начинайте с простого.</b> Если ваш проект небольшой, одной технологии API может быть достаточно. По мере роста вы сможете постепенно вводить дополнительные протоколы там, где они дают максимальный эффект.</p><p><b>Измеряйте результаты.</b> Внедрение новой технологии должно решать конкретные проблемы: снижать задержки, ускорять разработку или улучшать пользовательский опыт. Без измеримых целей гибридная архитектура превращается в ненужное усложнение.</p><p>Главное — сохранять архитектурную гибкость. Технологии продолжат меняться, и ваша система должна быть готова адаптироваться к новым вызовам.</p><h2>Итоги: не следуйте трендам, решайте задачи</h2><p>GraphQL не умер — он занял свою нишу в мире API. gRPC и tRPC не заменят его полностью, а дополнят экосистему, предлагая решения для конкретных сценариев.</p><p>Выбирайте технологию исходя из потребностей проекта, а не модных трендов. Иногда простое REST API может оказаться лучшим решением, если ваши требования минимальны.</p><p>Технологии продолжат развиваться. Важно сохранять архитектурную гибкость и не замыкаться на одном стеке. Умение выбрать правильный инструмент для задачи — навык, который останется актуальным независимо от появления новых технологий.</p><p>Главное — решать реальные проблемы, а не создавать себе новые в погоне за модными фреймворками.</p>]]></content:encoded>
    </item>
  </channel>
</rss>