Encoding

The gRPC API for sending and receiving is based upon messages. However, messages cannot be transmitted directly over a network; they must first be converted into bytes. This document describes how gRPC-Go converts messages into bytes and vice-versa for the purposes of network transmission.

Codecs (Serialization and Deserialization)

A Codec contains code to serialize a message into a byte slice (Marshal) and deserialize a byte slice back into a message (Unmarshal). Codecs are registered by name into a global registry maintained in the encoding package.

Implementing a Codec

A typical Codec will be implemented in its own package with an init function that registers itself, and is imported anonymously. For example:

package proto

import "google.golang.org/grpc/encoding"

func init() {
	encoding.RegisterCodec(protoCodec{})
}

// ... implementation of protoCodec ...

For an example, gRPC's implementation of the proto codec can be found in encoding/proto.

Using a Codec

By default, gRPC registers and uses the “proto” codec, so it is not necessary to do this in your own code to send and receive proto messages. To use another Codec from a client or server:

package myclient

import _ "path/to/another/codec"

Codecs, by definition, must be symmetric, so the same desired Codec should be registered in both client and server binaries.

On the client-side, to specify a Codec to use for message transmission, the CallOption CallContentSubtype should be used as follows:

	response, err := myclient.MyCall(ctx, request, grpc.CallContentSubtype("mycodec"))

As a reminder, all CallOptions may be converted into DialOptions that become the default for all RPCs sent through a client using grpc.WithDefaultCallOptions:

	myclient := grpc.Dial(ctx, target, grpc.WithDefaultCallOptions(grpc.CallContentSubtype("mycodec")))

When specified in either of these ways, messages will be encoded using this codec and sent along with headers indicating the codec (content-type set to application/grpc+<codec name>).

On the server-side, using a Codec is as simple as registering it into the global registry (i.e. importing it). If a message is encoded with the content sub-type supported by a registered Codec, it will be used automatically for decoding the request and encoding the response. Otherwise, for backward-compatibility reasons, gRPC will attempt to use the “proto” codec. In an upcoming change (tracked in this issue), such requests will be rejected with status code Unimplemented instead.

Compressors (Compression and Decompression)

Sometimes, the resulting serialization of a message is not space-efficient, and it may be beneficial to compress this byte stream before transmitting it over the network. To facilitate this operation, gRPC supports a mechanism for performing compression and decompression.

A Compressor contains code to compress and decompress by wrapping io.Writers and io.Readers, respectively. (The form of Compress and Decompress were chosen to most closely match Go's standard package implementations of compressors. Like Codecs, Compressors are registered by name into a global registry maintained in the encoding package.

Implementing a Compressor

A typical Compressor will be implemented in its own package with an init function that registers itself, and is imported anonymously. For example:

package gzip

import "google.golang.org/grpc/encoding"

func init() {
	encoding.RegisterCompressor(compressor{})
}

// ... implementation of compressor ...

An implementation of a gzip compressor can be found in encoding/gzip.

Using a Compressor

By default, gRPC does not register or use any compressors. To use a Compressor from a client or server:

package myclient

import _ "google.golang.org/grpc/encoding/gzip"

Compressors, by definition, must be symmetric, so the same desired Compressor should be registered in both client and server binaries.

On the client-side, to specify a Compressor to use for message transmission, the CallOption UseCompressor should be used as follows:

	response, err := myclient.MyCall(ctx, request, grpc.UseCompressor("gzip"))

As a reminder, all CallOptions may be converted into DialOptions that become the default for all RPCs sent through a client using grpc.WithDefaultCallOptions:

	myclient := grpc.Dial(ctx, target, grpc.WithDefaultCallOptions(grpc.UseCompresor("gzip")))

When specified in either of these ways, messages will be compressed using this compressor and sent along with headers indicating the compressor (content-coding set to <compressor name>).

On the server-side, using a Compressor is as simple as registering it into the global registry (i.e. importing it). If a message is compressed with the content coding supported by a registered Compressor, it will be used automatically for decompressing the request and compressing the response. Otherwise, the request will be rejected with status code Unimplemented.