tonic icon indicating copy to clipboard operation
tonic copied to clipboard

Client trait to allow for generic wrappers

Open gautamg795 opened this issue 2 years ago • 4 comments
trafficstars

This is related to #671 though I didn't want to bump the old issue. It would be really helpful if there were a common trait implemented by all tonic clients that contained functions like with_interceptor, with_origin, etc.

I think previous issues on this topic were for the purposes of mocking which is appropriately handled by the example in the repo, but this doesn't solve the issue of wanting to write generic client wrappers.

For example, I'd like to create a wrapper that adds a mandatory interceptor for all outgoing requests, regardless of which service it's to.

Something like

struct RpcWrapper<T: TonicClient> {
   client: T
}
impl<T: TonicClient> RpcWrapper<T> {
   fn new(channel: Channel) -> Self {
   		RpcWrapper {
            client: T::with_interceptor(channel, MyInterceptor)
        }
   }
}

and then with an appropriate Deref impl, this wrapper should otherwise act exactly like the concrete client type.

gautamg795 avatar Aug 31 '23 23:08 gautamg795

I was going to bump the other thread too, but I'm not sure this request is exactly what I'm looking for either.

I have a client that can I want to support either working offline OR integrating with a backend service depending on the user's preference. I was just looking to use the client interface as the interface itself, rather than wrapping, but I'm not sure it makes sense to have to write a full server implementation and then talk over a connection, even if it's local. I was hoping I could just do something like this

service MyService {
  rpc Echo (EchoRequest) returns (EchoReply) {}
}
struct LocalClient;

impl MyServiceClient for LocalClient {

        pub async fn echo(
            &mut self,
            request: impl tonic::IntoRequest<super::EchoRequest>,
        ) -> std::result::Result<tonic::Response<super::EchoReply>, tonic::Status> {
                Ok{
                    Response{
                        message: EchoReply{..}
                    }
                }
        }
}

or something like that. Maybe I'm polluting my APIs too much and I should wrap this in something, but it would seem reasonable to have the client interface be a trait, no?

Falmarri avatar Jan 15 '24 06:01 Falmarri

Was looking around hoping to find a common solution for this as well. Would be nice to not have to manually add interceptors to every initialized client and instead have a common trait that allows for the sort of abstraction you're describing.

solidiquis avatar Jun 02 '24 16:06 solidiquis