The TsgcGRPCClient component brings gRPC to Delphi and C++Builder without any external runtime. It is part of the sgcWebSockets Enterprise edition and runs on Windows, macOS, Linux, iOS and Android. This guide explains how the client works, how to configure it, and how to make each of the four gRPC call types from Delphi.
How it works
gRPC is Protocol Buffers messages framed over HTTP/2. Each message is sent as a length-prefixed payload on an HTTP/2 stream, the request carries headers such as content-type: application/grpc and grpc-timeout, and the final status arrives as the grpc-status and grpc-message trailers.
sgcWebSockets already ships a complete HTTP/2 stack, so TsgcGRPCClient sits on top of a TsgcHTTP2Client transport. You give it your serialized request bytes, it does the framing, header and timeout work, opens the HTTP/2 stream, and parses the response and trailers back into a typed TsgcGRPCResponse. Because the client works with raw TBytes, you can pair it with any Protocol Buffers library you already use.
Setting up the client
A gRPC channel is an HTTP/2 connection. Create a TsgcHTTP2Client, point it at the host and port, then assign it to the Client property of the gRPC component. For TLS, the HTTP/2 client uses OpenSSL or Windows SChannel; for a local plaintext server (h2c), set TLS to False.
uses
sgcHTTP2, sgcGRPC_Client, sgcGRPC_Classes, sgcGRPC_Types;
var
HTTP2: TsgcHTTP2Client;
GRPC: TsgcGRPCClient;
begin
HTTP2 := TsgcHTTP2Client.Create(nil);
HTTP2.Host := 'grpc.example.com';
HTTP2.Port := 443;
HTTP2.TLS := True; // False for a local h2c server
HTTP2.TLSOptions.IOHandler := iohOpenSSL; // or iohSChannel on Windows
GRPC := TsgcGRPCClient.Create(nil);
GRPC.Client := HTTP2;
end;
Configuring the channel
Channel-wide settings live in ChannelOptions. You can switch on per-message gzip compression, choose the wire content type, and raise the message and metadata size limits.
// gzip-compress outgoing messages
GRPC.ChannelOptions.Compression := grpcGzip; // grpcNoCompression, grpcGzip, grpcDeflate, grpcSnappy
// application/grpc+proto (default) or application/grpc+json
GRPC.ChannelOptions.ContentType := grpcProto; // or grpcJSON
// raise the limits for large messages
GRPC.ChannelOptions.MaxMessageSize := 16 * 1024 * 1024;
GRPC.ChannelOptions.MaxMetadataSize := 64 * 1024;
Metadata and authentication
Custom headers travel as gRPC metadata. Add them to DefaultMetadata to send them on every call, which is the usual place for an authorization token or a tracing header.
GRPC.DefaultMetadata.Add('authorization', 'Bearer eyJ...');
GRPC.DefaultMetadata.Add('x-api-key', 'my-api-key');
Deadlines and cancellation
A per-call timeout is sent as the standard grpc-timeout header, so the server can give up at the same moment your client does. An in-flight streaming call can be stopped at any time with CancelCall, passing the stream id returned when the stream was opened.
Unary calls
A unary call sends one request and gets one response. Call blocks until the reply arrives and returns a TsgcGRPCResponse with the StatusCode, StatusMessage, the raw Data bytes (or DataString) and the Trailers.
var
oResponse: TsgcGRPCResponse;
begin
oResponse := GRPC.Call('helloworld.Greeter', 'SayHello', RequestBytes);
if oResponse.StatusCode = grpcOK then
Memo1.Text := oResponse.DataString
else
ShowMessage('gRPC error ' + oResponse.StatusMessage);
end;
To keep the UI responsive, use CallAsync. It returns at once and delivers the reply through the OnGRPCResponse event.
GRPC.OnGRPCResponse := GRPCResponse;
GRPC.CallAsync('helloworld.Greeter', 'SayHello', RequestBytes);
procedure TForm1.GRPCResponse(Sender: TObject; const Response: TsgcGRPCResponse);
begin
if Response.StatusCode = grpcOK then
Memo1.Text := Response.DataString;
end;
Server streaming
With server streaming you send one request and the server returns a stream of messages. Each message raises OnGRPCStreamMessage, and OnGRPCStreamEnd fires once with the final status.
GRPC.OnGRPCStreamMessage := GRPCStreamMessage;
GRPC.OnGRPCStreamEnd := GRPCStreamEnd;
GRPC.ServerStreamingCall('chat.Feed', 'Subscribe', RequestBytes);
procedure TForm1.GRPCStreamMessage(Sender: TObject; aStreamId: Integer;
const aData: TBytes);
begin
Memo1.Lines.Add(DecodeMessage(aData));
end;
Client streaming
Client streaming is the mirror image: you push a stream of messages and the server replies once. Open the stream, send each message, then close it to read the single reply.
var
vStreamId: Integer;
oResponse: TsgcGRPCResponse;
begin
vStreamId := GRPC.OpenClientStream('upload.Service', 'Send');
GRPC.SendStreamMessage(vStreamId, ChunkBytes1);
GRPC.SendStreamMessage(vStreamId, ChunkBytes2);
oResponse := GRPC.CloseClientStream(vStreamId);
if oResponse.StatusCode = grpcOK then
ShowMessage('Upload accepted');
end;
Bidirectional streaming
Bidirectional streaming runs a full-duplex exchange over a single HTTP/2 stream: both sides send whenever they like. Open the stream, send messages as needed, handle incoming messages in OnGRPCStreamMessage, and close when finished.
var
vStreamId: Integer;
begin
vStreamId := GRPC.OpenBidiStream('chat.Room', 'Connect');
GRPC.SendBidiMessage(vStreamId, EncodeMessage('hello'));
// ... incoming messages arrive on OnGRPCStreamMessage ...
GRPC.CloseBidiStream(vStreamId);
end;
Status codes and error handling
Every response carries a typed StatusCode from grpcOK through the standard gRPC set (grpcNOT_FOUND, grpcUNAVAILABLE, grpcDEADLINE_EXCEEDED, grpcUNAUTHENTICATED and the rest). For asynchronous and streaming calls, OnGRPCError reports a non-OK gRPC status and OnGRPCException reports a transport or connection failure.
GRPC.OnGRPCError := GRPCError;
procedure TForm1.GRPCError(Sender: TObject; aStreamId: Integer;
aStatusCode: TsgcGRPCStatusCode; const aStatusMessage: string);
begin
Memo1.Lines.Add(Format('gRPC error %d: %s', [Ord(aStatusCode), aStatusMessage]));
end;
Automatic retry
The client can retry failed calls for you. Enable RetryPolicy, set the attempt count and backoff, and list the status codes that should trigger a retry. This is the typical configuration for transient grpcUNAVAILABLE failures.
GRPC.RetryPolicy.Enabled := True;
GRPC.RetryPolicy.MaxAttempts := 4;
GRPC.RetryPolicy.InitialBackoff := 200; // ms
GRPC.RetryPolicy.BackoffMultiplier := 2.0;
GRPC.RetryPolicy.RetryableStatusCodes :=
GRPC.RetryPolicy.RetryableStatusCodes + [grpcUNAVAILABLE, grpcRESOURCE_EXHAUSTED];
For cross-cutting logic such as logging or refreshing a token, add an entry to the Interceptors chain, which wraps every call in one place.
Where to go next
On top of this generic client, sgcWebSockets ships typed clients for the Google Cloud gRPC services (Pub/Sub, Speech-to-Text, Translation, Vision, Natural Language, Cloud Storage, BigQuery and Vertex AI), so you call high-level methods instead of assembling protobufs by hand. A ready-to-run sample is in Demos\21.GRPC\01.GRPC_Client, and the full reference is on the gRPC Client product page.
Questions or help getting started? Get in touch. You will get a reply from the people who wrote the code.
