Protocols & Codecs
Overview
Section titled “Overview”connect-kotlin-server implements three wire protocols from the Connect family: Connect unary (simple non-enveloped), Connect streaming (enveloped), and gRPC-Web (enveloped). Each protocol carries messages encoded in one of two codecs: proto binary or protobuf-JSON. Protocol and codec are negotiated transparently from the Content-Type header on each request.
Protocol Selection
Section titled “Protocol Selection”The HTTP Content-Type header (both request and response) determines which protocol is used:
| Content-Type | Protocol | Message framing | Use case |
|---|---|---|---|
application/proto, application/x-protobuf, application/protobuf | Connect unary | Non-enveloped | Unary RPC only; lowest overhead |
application/json | Connect unary | Non-enveloped | Unary RPC only; human-readable |
application/connect+proto | Connect streaming | 5-byte enveloped | Streaming over Connect protocol |
application/connect+json | Connect streaming | 5-byte enveloped | Streaming with JSON codec |
application/grpc-web+proto | gRPC-Web | 5-byte enveloped | Browser clients; streaming support |
application/grpc-web+json | gRPC-Web | 5-byte enveloped | Browser clients with JSON codec |
The negotiation is case-insensitive and strips charset parameters. If no Content-Type is provided or it is unsupported, the request fails with HTTP 415 Unsupported Media Type.
Codecs
Section titled “Codecs”Each request specifies its encoding through the codec inferred from the Content-Type (or the encoding parameter for GET requests).
Proto Binary (proto)
Section titled “Proto Binary (proto)”Uses the standard Protocol Buffers binary wire format. Maps to application/proto and variants:
// Internally uses protobuf-java's standard serializationmessage.toByteArray() // serializeprototype.parserForType.parseFrom(data) // deserializeCharacteristics:
- Size: compact binary encoding
- Speed: fastest serialization/deserialization
- Human-readable: no; requires a
.protoschema to inspect
Protobuf-JSON (json)
Section titled “Protobuf-JSON (json)”Uses the canonical Protobuf JSON representation, backed by protobuf-java-util’s JsonFormat:
// Omits insignificant whitespace; resolves google.protobuf.Any via TypeRegistryprinter.print(message).toByteArray(StandardCharsets.UTF_8)parser.merge(jsonString, builder)Characteristics:
- Size: larger than binary; compresses well
- Speed: slower than binary
- Human-readable: yes; fully compatible with browser clients and JSON tooling
- Any support: resolves
google.protobuf.Anyfields if types are registered
Message Framing
Section titled “Message Framing”Non-enveloped (Connect unary)
Section titled “Non-enveloped (Connect unary)”The message body is the serialized protobuf directly—no framing:
[message bytes]Only supported for unary requests. Responses use the same format. Error responses are always JSON (see error handling).
Enveloped (Connect streaming & gRPC-Web)
Section titled “Enveloped (Connect streaming & gRPC-Web)”Both Connect streaming and gRPC-Web use a 5-byte length-prefixed envelope format for each message:
[flags:1][length:4 big-endian][data:length]- flags (1 byte):
- Bit 0 (
0x01): message data is compressed - Bit 1 (
0x02): Connect streaming end-of-stream marker - Bit 7 (
0x80): gRPC-Web trailer frame (status + headers)
- Bit 0 (
- length (4 bytes, big-endian): byte count of data, excludes the 5-byte header
- data (variable): the serialized message or framing payload
Connect streaming end-of-stream
Section titled “Connect streaming end-of-stream”After the final message, Connect streaming sends a single envelope with the FLAG_CONNECT_END_STREAM flag set. The data is a JSON object with optional error and metadata fields (or empty if the call succeeded).
gRPC-Web trailers
Section titled “gRPC-Web trailers”After the final message, gRPC-Web sends a single envelope with the FLAG_GRPC_WEB_TRAILER flag. The data is an HTTP/1 header block (key-value pairs) containing the gRPC status, message, and any error details.
Method Support Matrix
Section titled “Method Support Matrix”| RPC type | Connect unary | Connect streaming | gRPC-Web |
|---|---|---|---|
| Unary | ✅ | ✅ | ✅ |
| Server streaming | — | ✅ | ✅ |
| Client streaming / bidirectional | — | — | — |
Unary methods work on all three protocols; the protocol is selected by Content-Type.
Server streaming requires an enveloped protocol (Connect streaming or gRPC-Web); the non-enveloped Connect protocol does not support streaming.
Client streaming and bidirectional RPC are not supported: the dispatcher handles unary and server-streaming only. (The embedded server can serve HTTP/2 cleartext when connect.server.http2 is enabled, but these RPC kinds are not yet wired.)
GET for Idempotent Unary Methods
Section titled “GET for Idempotent Unary Methods”Unary methods marked with idempotency_level = NO_SIDE_EFFECTS in their .proto definition can be invoked via HTTP GET:
curl 'localhost:8080/package.Service/Method?encoding=json&message=%7B%7D'Query parameters:
| Name | Required | Purpose |
|---|---|---|
encoding | Yes | Codec: json or proto |
message | Yes | URL-safe base64 or UTF-8 JSON string (see base64 parameter) |
base64 | No | If 1, decode message as URL-safe base64 instead of UTF-8 JSON |
compression | No | Compression codec (e.g., gzip); only for proto-encoded messages |
connect | No if requireProtocolVersion is false | Version check: must be v1 |
GET is disabled by default; enable it with the connect.server.get-enabled property or ConnectServerConfig.getEnabled = true.
[!TIP] GET is useful for browser bookmarks and CDN caching of read-only operations. Since the message is passed in the query string, it is visible in logs and browser history — do not use for sensitive data.
Example: Content Negotiation
Section titled “Example: Content Negotiation”Given a POST to POST /myapp.v1.EchoService/Echo:
Content-Type: application/connect+proto→ Protocol: Connect streaming, Codec: proto binary, Framing: enveloped
→ Request and response messages are framed with the 5-byte envelope, suitable for streaming.
Content-Type: application/json→ Protocol: Connect unary, Codec: protobuf-JSON, Framing: non-enveloped
→ Request and response bodies are raw JSON; only unary methods are allowed.
Content-Type: application/grpc-web+json→ Protocol: gRPC-Web, Codec: protobuf-JSON, Framing: enveloped
→ Response includes a gRPC-Web trailer frame; suitable for browser clients.
[!NOTE] The response
Content-Typealways matches the request protocol (though codec preference may be influenced by client Accept headers). See the Connect spec and gRPC-Web spec for full details on header semantics.