Interceptors
Interceptors let you observe and modify outbound requests and inbound responses for both unary and streaming RPCs.
Each interceptor is instantiated once per request. It exposes hooks the client invokes at each step of the request lifecycle, where you can read or replace the headers, body, trailers, or errors.
For example, here is an interceptor that adds an Authorization header to
outbound requests destined for the demo.connectrpc.com host. Request types
are immutable: to mutate one, use the clone() extension function on
UnaryHTTPRequest (for unary calls) or HTTPRequest (for streaming calls).
import com.connectrpc.Interceptorimport com.connectrpc.StreamFunctionimport com.connectrpc.UnaryFunctionimport com.connectrpc.http.clone
// Interceptor that adds an `Authorization` header to outbound// requests to `demo.connectrpc.com`.class AuthorizationInterceptor : Interceptor { override fun unaryFunction(): UnaryFunction { return UnaryFunction( requestFunction = { request -> if (request.url.host != "demo.connectrpc.com") { return@UnaryFunction request } val headers = request.headers.toMutableMap() headers["Authorization"] = listOf("SOME_USER_TOKEN") request.clone(headers = headers) }, responseFunction = { response -> response }, ) }
override fun streamFunction(): StreamFunction { return StreamFunction( requestFunction = { request -> if (request.url.host != "demo.connectrpc.com") { return@StreamFunction request } val headers = request.headers.toMutableMap() headers["Authorization"] = listOf("SOME_USER_TOKEN") request.clone(headers = headers) }, ) }}Interceptors are registered with the ProtocolClient on initialization. The
interceptors field accepts a list of factory functions; each factory
receives the ProtocolClientConfig and returns an interceptor instance.
val client = ProtocolClient( httpClient = ConnectOkHttpClient(OkHttpClient()), ProtocolClientConfig( host = "https://demo.connectrpc.com", serializationStrategy = GoogleJavaLiteProtobufStrategy(), networkProtocol = NetworkProtocol.CONNECT, interceptors = listOf({ _: ProtocolClientConfig -> AuthorizationInterceptor() }), ),)The client will invoke each interceptor in FIFO order on the request path, and in LIFO order on the response path.
For example, with four interceptors A, B, C, D registered in order:
interceptors = listOf( { _: ProtocolClientConfig -> A() }, { _: ProtocolClientConfig -> B() }, { _: ProtocolClientConfig -> C() }, { _: ProtocolClientConfig -> D() },)their hooks fire in this order:
Client -> A -> B -> C -> D -> ServerClient <- D <- C <- B <- A <- Server