feat(api-core): add ClientInterceptor and apply_interceptors helper - #18236
feat(api-core): add ClientInterceptor and apply_interceptors helper#18236chalmerlowe wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the apply_interceptors helper function to sequentially apply a list of client interceptors to a gRPC channel, along with comprehensive unit tests verifying its behavior. The reviewer feedback correctly points out that applying interceptors sequentially in a loop introduces unnecessary nesting overhead and reverses the standard gRPC execution order. To resolve this, the reviewer suggests unpacking the interceptors directly into a single grpc.intercept_channel call and updating the corresponding execution order test assertion.
…terceptor unit tests
|
|
||
| def apply_interceptors( | ||
| channel: grpc.Channel, | ||
| interceptors: Optional[Sequence[ClientInterceptor]] = None, |
There was a problem hiding this comment.
In your other PR, I suggested accepting Callable wrappers here as an alternate interceptor type, to support the otel interceptor.
That would make this into something like:
modified_channel = channel
for interceptor in interceptors or []:
if isinstance(interceptor, ClientInterceptor):
modified_channel = grpc.intercept_channel(channel, interceptor)
else:
modified_channel = interceptor(modified_channel)
return modified channel
Let me know if you think that could work
Problem
Generated client libraries currently lack a standardized, centralized helper in
google-api-coreto apply client interceptors to a gRPC channel. Without a shared helper, each client library would need duplicate channel interceptor wrapping logic.Solution
This change introduces interceptor utilities in
google.api_core.grpc_helpers:ClientInterceptor: A generic type alias representing client-side gRPC interceptors across unary and streaming modes.apply_interceptors: A utility function that applies an optional list of interceptors to a gRPC channel in a single call viagrpc.intercept_channel(channel, *interceptors). If no interceptors are provided, it returns the original channel unmodified.Notes for Reviewers
grpc.intercept_channel(channel, *interceptors)delegates directly to gRPC's native variadic API and ensures standard execution order where the first interceptor in the sequence executes first on outbound requests.