I am looking to add grpc support to mobile networking stack at my workplace and was wondering if we can simplify the clientInterceptor interface. I do understand the reasons for it being a little complicated, but we could come up with a simpler one. I am by no means an expert in grpc, but wanted to see if we can simplify efforts required by the devs.
This is not a breaking change, my proposal is to introduce a simpler abstract class which devs can choose to extend rather than implementing ClientInterceptor. I come from java land and so the proposal is in java, but should be generalizable.
public abstract class SimpleClientInterceptor<ReqT, RespT> {
/** * Invoked with outgoing request headers. * @param requestHeaders request headers that are sent as part of the request. */ protected abstract void onRequestHeaders(Metadata requestHeaders);
/** * Invoked when a message is sent out from client to server. * @param message message being sent out. */ protected abstract void onRequestMessage(ReqT message);
/** * Invoked with response headers. * @param responseHeaders response headers that are received from the server. */ protected abstract void onResponseHeaders(Metadata responseHeaders);
/** * Invoked with message received from the server. * @param msg message being received. */ protected abstract void onResponseMessage(RespT msg);
/** * Invoked when the call is closed. * @param status * @param trailers */ protected void onClose(Status status, Metadata trailers) {}
} |
Here is the
impl draft on how we could achieve this. Basic idea is to add a ClientCallHandler/wrapper and call into the interceptor impl where ever required.
As of today, an interceptor which just processes headers looks complicated as below.
public class HeaderClientInterceptor extends InterceptorChannel {
public HeaderClientInterceptor(InterceptorChannel next){ super(next); }
@Override public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions) { return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override public void start(Listener<RespT> responseListener, Metadata headers) { // process request headers. add/edit/remove headers. super.start(new SimpleForwardingClientCallListener<RespT>(responseListener) { @Override public void onHeaders(Metadata headers) { super.onHeaders(headers); } }, headers); } }; }
@Override public String authority() { return next.authority(); } }
|
Definitely, this looks complicated just to process/edit request headers and demands a learning curve for someone who is looking to implement an interceptor.
With the new proposal, an interceptor which accesses some headers would be like below.
public class HeaderInterceptor<ReqT, RespT> extends SimpleClientInterceptor<ReqT, RespT> {
public HeaderInterceptor(InterceptorChannel next) { super(next); }
@Override protected void onRequestHeaders(Metadata requestHeaders) { // process request headers. add/ edit / remove headers }
@Override protected void onRequestMessage(ReqT message) { }
@Override protected void onResponseHeaders(Metadata responseHeaders) { // process response headers. add/edit/remove }
@Override protected void onResponseMessage(RespT msg) { }
} |
Implementors don't need to worry about calling next entity in the chain as its taken care by the CallHandler/wrapper. More details can be checked out
here on how to get this done.
Just a reminder, that this is not a breaking change, just that a new abstract class will be introduced which devs can use if they want to, instead of the ClientInterceptor interface directly.
Would love to hear your thoughts.
--