REST s JSON, nebo gRPC s Protobuf?

REST s JSON je textové API nad běžným HTTP, které přečte prohlížeč, curl i člověk. gRPC volá metody služeb definovaných v souboru .proto a posílá binární zprávy Protocol Buffers přes HTTP/2. Mezi vlastními službami šetří gRPC bajty a dává typový kontrakt; pro veřejné API, prohlížeče a integrace zůstává hlavním formátem JSON, v B2B a úředních formátech často XML.

Autor: Aktualizováno

Kdy co použít

  • REST a JSON pro veřejné API, prohlížeč, integrace s partnery, webhooky a všude, kde se API čte nástroji bez generovaného kódu. Kontrakt popisuje OpenAPI.
  • gRPC pro komunikaci vlastních služeb, kde ovládáš klienta i server, chceš generovaného klienta pro více jazyků, streamování a termíny volání (deadline).
  • XML tam, kde ho určuje standard nebo protistrana: SOAP, e-faktury, bankovní zprávy ISO 20022, úřední podání. Tam ho binární protokol nenahradí.

Rozhodnutí není buď–anebo. Častá architektura má gRPC uvnitř a JSON na hranici systému, často ze stejného souboru .proto (viz JSON jako druhá vrstva).

Kontrakt: soubor .proto

Zprávy a služby se popisují v jazyce Protocol Buffers. Každé pole má typ a číslo; binární zpráva obsahuje čísla polí, ne jejich jména. Z jednoho souboru generuje protoc nebo buf třídy a klienta pro Go, Javu, C#, Python, TypeScript a další jazyky.

proto/objednavka.proto
syntax = "proto3";

package eshop.v1;

import "google/protobuf/timestamp.proto";

message Polozka {
  string kod = 1;
  int32 pocet = 2;
  int64 cena_haleru = 3;
}

message Objednavka {
  string cislo = 1;
  repeated Polozka polozky = 2;
  google.protobuf.Timestamp vytvoreno = 3;
  bool expres = 4;
}

message DetailRequest {
  string cislo = 1;
}

service Objednavky {
  rpc Detail(DetailRequest) returns (Objednavka);            // jeden požadavek, jedna odpověď
  rpc Sledovat(DetailRequest) returns (stream Objednavka);   // server posílá změny průběžně
}

gRPC zná čtyři druhy metod: jeden požadavek a jedna odpověď, stream od serveru, stream od klienta a obousměrný stream. Klient může volání nastavit termín a server po jeho vypršení vrátí DEADLINE_EXCEEDED. Místo syntax = "proto3" nové soubory mohou používat edice (edition = "2024"), které proto2 a proto3 nahrazují; binární formát zůstává stejný.

Stejná zpráva jako JSON a jako Protobuf

Node.js 25, @bufbuild/protobuf 2.16
import { create, createFileRegistry, fromBinary, toBinary, toJson } from "@bufbuild/protobuf";
import { FileDescriptorSetSchema, timestampFromDate } from "@bufbuild/protobuf/wkt";
import { readFileSync } from "node:fs";

// set.binpb vytvořil příkaz: npx buf build -o set.binpb
const registry = createFileRegistry(fromBinary(FileDescriptorSetSchema, readFileSync("set.binpb")));
const Objednavka = registry.getMessage("eshop.v1.Objednavka");

const zprava = create(Objednavka, {
  cislo: "2026-117",
  polozky: [
    { kod: "HR-01", pocet: 2, cenaHaleru: 14990n },
    { kod: "TA-07", pocet: 1, cenaHaleru: 21900n },
  ],
  vytvoreno: timestampFromDate(new Date("2026-10-04T10:00:00Z")),
  expres: false,
});

const bin = toBinary(Objednavka, zprava);
const json = JSON.stringify(toJson(Objednavka, zprava));
Výstup
ProtoJSON: {"cislo":"2026-117","polozky":[{"kod":"HR-01","pocet":2,"cenaHaleru":"14990"},
           {"kod":"TA-07","pocet":1,"cenaHaleru":"21900"}],"vytvoreno":"2026-10-04T10:00:00Z"}
JSON bajtů: 161  Protobuf bajtů: 47
hex: 0a 08 32 30 32 36 2d 31 31 37 12 0c 0a 05 48 52 2d 30 31 10 02 18 8e 75 12 0d
     0a 05 54 41 2d 30 37 10 01 18 8c ab 01 1a 06 08 a0 c7 88 d6 06

Binární zpráva má 47 bajtů, JSON 161. Úspora vzniká hlavně tím, že se nepřenáší názvy klíčů a čísla jsou zakódovaná jako varint (8e 75 je 14990). Po kompresi gzip se rozdíl u větších odpovědí zmenšuje; porovnávej na svých datech, ne na jedné zprávě. Hex výpis bez souboru .proto nic neřekne: 0a 08 znamená „pole 1, řetězec délky 8“, jméno cislo v něm není.

Při ladění proto vývojáři čtou zprávy jako JSON. Nástroje typu grpcurl nebo buf curl si schéma vezmou z reflexe serveru nebo ze souboru .proto a výsledek vypíšou jako ProtoJSON.

ProtoJSON: kanonický JSON pro Protobuf

Protobuf definuje vlastní mapování na JSON, nazvané ProtoJSON. Je to obyčejný JSON text, ale s pravidly, která se liší od ručně psaného API:

  • Názvy polí se převádí na lowerCamelCase (cena_haleru → cenaHaleru). Parser přijme obě podoby.
  • int64 a uint64 se zapisují jako řetězce. Důvod je stejný jako u čísel v JSON: JavaScript a další parsery čtou čísla jako double a nad 253 ztrácejí přesnost.
  • bytes jsou řetězec v Base64, Timestamp řetězec RFC 3339 v UTC, enum jméno hodnoty.
  • Pole s výchozí hodnotou se nezapisují, proto v ukázce chybí "expres": false.
PastCo se děje
int64 jako řetězecProtoJSON zapíše int64 a uint64 jako "14990". Klient, který čeká číslo, selže nebo porovnává řetězce.
Chybějící výchozí hodnotyPole s výchozí hodnotou (false, 0, "") bez sledování přítomnosti se nezapíše; expres v ukázce chybí. Rozlišit „nezadáno“ pomůže optional.
Neznámá poleBinární parser je zachová a předá dál, JSON parser je podle specifikace odmítne, pokud ho výslovně nenastavíš jinak.
Přejmenování poleBinárně je bezpečné, rozhoduje číslo pole. JSON klíč se ale změní (cenaHaleru) a JSON klienti přestanou fungovat.
Znovupoužité číslo poleStarý klient přečte nová data jako starý význam. Smazaná čísla a jména označ reserved.

Srovnání

REST + JSONgRPC + Protobuf
PřenosHTTP/1.1, HTTP/2 i HTTP/3HTTP/2; v prohlížeči jen přes gRPC-Web nebo transcoding
Kontraktvolitelný (OpenAPI, JSON Schema)povinný soubor .proto, z něj se generuje kód
Datatext, čitelný bez nástrojůbinární, ke čtení potřebuješ .proto
Model volánízdroje a metody HTTP (GET, POST…)volání metod služby, 4 druhy včetně obousměrného streamu
Chybystavový kód HTTP a tělo odpovědiHTTP 200 a grpc-status v trailerech
Cache a proxyběžná HTTP cache, CDN, logykaždé volání je POST, HTTP cache se nepoužije; proxy musí umět HTTP/2 a trailery
Typyjen to, co má JSON (číslo, řetězec…)int32/int64, bytes, enum, Timestamp…
Vývoj schématudohodou a verzí APIčísla polí; přejmenování je binárně kompatibilní

gRPC vrací HTTP 200 i při chybě aplikace a skutečný výsledek posílá v trailerech grpc-status a grpc-message. Monitoring, který sleduje jen stavové kódy HTTP, proto chyby gRPC nevidí. Každá zpráva má navíc pětibajtovou hlavičku (příznak komprese a délka), takže tělo odpovědi není samotná zpráva Protobuf.

JSON jako druhá vrstva nad gRPC

Prohlížeč neumí přímo pracovat s rámci HTTP/2 ani s trailery, takže klasického gRPC klienta nespustí. Existují dvě cesty:

  • gRPC-Web je upravený protokol (application/grpc-web), který prohlížeč posílá přes fetch. Mezi prohlížečem a službou obvykle stojí proxy, která ho překládá. Klient potřebuje generovaný kód a obousměrný stream nepodporuje.
  • JSON transcoding zpřístupní metody gRPC jako REST s JSON podle anotace google.api.http. Umí to grpc-gateway (samostatný proxy server), Envoy nebo ASP.NET Core přímo v aplikaci. Klient nepotřebuje nic o gRPC vědět.
Anotace pro JSON transcoding
service Objednavky {
  rpc Detail(DetailRequest) returns (Objednavka) {
    option (google.api.http) = { get: "/v1/objednavky/{cislo}" };
  }
}

// stejná metoda je pak dostupná i jako
// GET /v1/objednavky/2026-117   →   200, application/json (ProtoJSON)

JSON odpověď z transcodingu se řídí pravidly ProtoJSON, včetně řetězců u int64 a vynechaných výchozích hodnot; konkrétní implementace to umí nastavit. Pokud ji publikuješ jako veřejné API, dokumentuj tato pravidla. Hodí se i OpenAPI popis vygenerovaný ze stejného souboru .proto.

Časté chyby

  • gRPC kvůli výkonu bez měření. U API, kde rozhoduje databáze nebo síťová latence, velikost zprávy často nehraje roli. Změř to.
  • Veřejné API jen v gRPC. Partneři potřebují generátor, proxy pro HTTP/2 a znalost .proto. Pro integrace bývá jednodušší REST.
  • Ruční JSON místo ProtoJSON. Pokud JSON vyrábíš z protobuf zpráv, použij serializátor knihovny. Ruční převod se rozejde v int64, výchozích hodnotách a názvech polí.
  • Změna čísla nebo typu pole. Zpětnou kompatibilitu kontroluje buf breaking; spouštěj ho v CI proti poslední vydané verzi.

Zdroje

gRPC: Core concepts, gRPC over HTTP2, gRPC-Web protocol, ProtoJSON Format, Protobuf Editions a gRPC JSON transcoding v ASP.NET Core. Další binární alternativy k JSON (CBOR, MessagePack, BSON) popisuje kapitola binární formáty.