Skip to main content

Using clients

Configuration

Supported protocols

Connect-Kotlin currently supports 3 protocols:

  • The new Connect protocol, a simple, HTTP-based protocol that works over HTTP/1.1 or HTTP/2. It takes the best parts of gRPC/gRPC-Web, including streaming, and packages them into a protocol that works well on all platforms, including mobile. By default, JSON- and binary-encoded Protobuf is supported.
  • The gRPC protocol: Allows clients to communicate with existing gRPC services.
  • The gRPC-Web protocol: Allows clients to communicate with existing gRPC-Web services. The main difference between gRPC and gRPC-Web is that gRPC-Web does not utilize HTTP trailers in the protocol.

If your backend services are already using gRPC today, Envoy provides support for converting requests made using the Connect and gRPC-Web protocols to gRPC.

Switching between these protocols is a simple 1-line code change when configuring the ProtocolClientConfig's protocol field:

val client = ProtocolClient(
httpClient = ConnectOkHttpClient(OkHttpClient()),
ProtocolClientConfig(
host = host,
serializationStrategy = GoogleJavaProtobufStrategy(),
protocol = Protocol.CONNECT, // Protocol.GRPC or Protocol.GRPC_WEB.
),
)

Note that these Protocol options are mutually exclusive. An instance of a client can only be associated with a single protocol. To use both protocols with different APIs in the same application, the recommended solution would be to create a specific ProtocolClient for each protocol.

Compression

Request compression and response decompression are provided through options that register compression pools containing logic for compressing and decompressing data. Gzip support is provided by default, and support for additional compression algorithms can be provided by replicating the functionality provided by the GzipCompressionPool.

HTTP stack

By default, HTTP networking is done using OkHttp via the ConnectOkHttpClient wrapper. Its constructor accepts an OkHttpClient to use for the underlying network library. Furthermore, ConnectOkHttpClient is just the OkHttp implementation of the HTTPClientInterface. If there is another preferred networking library, it is possible to provide a custom client to use with Connect-Kotlin!

Using generated clients

Coroutines

Generated clients support Kotlin coroutine APIs, making it easy to use Connect generated code in coroutine contexts:

// ProtocolClient is usually stored and passed to generated clients.
val client = ProtocolClient(
httpClient = ConnectOkHttpClient(OkHttpClient()),
ProtocolClientConfig(
host = "https://demo.connectrpc.com", // Base URL for APIs.
serializationStrategy = GoogleJavaProtobufStrategy(), // There is also the GoogleJavaJSONStrategy and GoogleJavaLiteProtobufStrategy.
protocol = Protocol.CONNECT, // GRPC and GRPC_WEB are also options.
)
)
// Create the Eliza service client.
val elizaServiceClient = ElizaServiceClient(client)
// Perform the request with the lifecycleScope.
lifecycleScope.launch(Dispatchers.IO) {
// Make unary request to Eliza.
val response = elizaServiceClient.say(SayRequest.newBuilder().setSentence("Hello, Eliza").build())
response.success { success ->
// Get Eliza's reply from the response and print it.
val elizaSentence = success.message.sentence
println(elizaSentence)
}
response.error { error ->
// Handle any errors from the request.
}
}

For server-streaming RPCs, the corresponding method on the client returns a *StreamInterface object which allows the caller to send data over the stream and to iterate over updates from the server using a RecieveChannel:

val stream = elizaServiceClient.converse()
lifecycleScope.launch(Dispatchers.IO) {
async {
for (streamResult in stream.resultChannel()) {
streamResult.maybeFold(
onMessage = { result ->
// Update the view with the response.
val elizaResponse = result.message
println(elizaResponse)
},
)
}
}
// Add the message the user is sending to the views.
stream.send(ConverseRequest.newBuilder().setSentence("Hello, Eliza").build())
}

Callbacks

If a callback-based approach is preferred, callbacks/closures can be used instead for unary methods. Streaming callback-based methods are not currently supported.

These methods are not generated by default, but are configurable using the generateCallbackMethods option:

// ProtocolClient is usually stored and passed to generated clients.
val client = ProtocolClient(
httpClient = ConnectOkHttpClient(OkHttpClient()),
ProtocolClientConfig(
host = "https://demo.connectrpc.com", // Base URL for APIs.
serializationStrategy = GoogleJavaProtobufStrategy(), // There is also the GoogleJavaJSONStrategy and GoogleJavaLiteProtobufStrategy.
protocol = Protocol.CONNECT, // GRPC and GRPC_WEB are also options.
)
)
// Create the Eliza service client.
val elizaServiceClient = ElizaServiceClient(client)
...
val cancelable = elizaServiceClient.say(SayRequest.newBuilder().setSentence("hello").build()) { response ->
response.success { result ->
println(result.message)
}
}
// cancelable() can be used to cancel the underlying request.