grpc-dart icon indicating copy to clipboard operation
grpc-dart copied to clipboard

Async client interceptors?

Open acoutts opened this issue 2 years ago • 10 comments

I would like to perform an async operation within an interceptor. The problem is it has to return a ResponseFuture, not a Future, so I cannot mark the interceptUnary method as async and perform asynchronous code within it (like access the platform method channel).

Is there a way to work around this to perform async operations within the interceptor?

3.0.2

Repro steps

  @override
  ResponseFuture<R> interceptUnary<Q, R>(
    ClientMethod<Q, R> method,
    Q request,
    CallOptions options,
    ClientUnaryInvoker<Q, R> invoker,
  ) async { } // error

acoutts avatar Apr 07 '22 22:04 acoutts

There are many issues and pull requests for this. Waiting https://github.com/grpc/grpc-dart/pull/489 to be merged.

esenmx avatar Apr 12 '22 10:04 esenmx

Any Solution?

lazicah avatar Oct 08 '22 21:10 lazicah

Any update/workaround?

EnesKaraosman avatar Nov 16 '22 14:11 EnesKaraosman

@EnesKaraosman you should probably use this code as a solution

mraleph avatar Nov 16 '22 20:11 mraleph

@EnesKaraosman you should probably use this code as a solution

Tried this one but received syntax issues with dart 2.18.4

EnesKaraosman avatar Nov 16 '22 20:11 EnesKaraosman

Tried this one but received syntax issues with dart 2.18.4

Well, you most likely can fix them. The code should still work but needs to be updated.

mraleph avatar Nov 16 '22 20:11 mraleph

Hi thanks for this solutions, but how I can return an custom error in the interceptor?

lazicah avatar Nov 22 '22 00:11 lazicah

@lazicah You can rethrow them and handle via your Controller/Bloc etc... If you are talking about really returning, you can't and shouldn't.

esenmx avatar Nov 22 '22 08:11 esenmx

@mraleph it is very useful to have Async interceptStreaming as well. For example we want retrive Firebase Token in the interceptor - it will affect interceptStreaming and interceptUnary

Ideally:

  @override
  Stream<R> interceptStreaming<Q, R>(
    ClientMethod<Q, R> method,
    Stream<Q> requests,
    CallOptions options,
    ClientStreamingInvoker<Q, R> invoker,
  ) async* {
    final token = await _getToken?.call();
    yield* invoker(method, requests, options.withToken(token));
  }

  @override
  FutureOr<R> interceptUnary<Q, R>(
    ClientMethod<Q, R> method,
    Q request,
    CallOptions options,
    ClientUnaryInvoker<Q, R> invoker,
  ) async {
    final token = await _getToken?.call();
    return invoker(method, request, options.withToken(token));
  }

zs-dima avatar Sep 09 '23 20:09 zs-dima

Came here looking for exactly the same need as @zs-dima . I would love to be able to just await in the intercept* methods. I've been trying to rework the workaround "retry" solution from @mraleph but I'm getting confused with the multiple layers of completers and futures.

natebot13 avatar May 07 '24 10:05 natebot13

After a lot of experimentation and nearly modifying the package for my own needs, I discovered metadataProviders which does exactly what I needed to modify the call options metadata before the request is made. I remember reading that field a while ago, but somehow ignored it, thinking an interceptor is what I really needed.

It turned out to be very simple:

@override
ResponseFuture<R> interceptUnary<Q, R>(
  ClientMethod<Q, R> method,
  Q request,
  CallOptions options,
  ClientUnaryInvoker<Q, R> invoker,
) {
  addToken(Map<String, String> metadata, String _) async {
    final token = await FirebaseAuth.instance.currentUser?.getIdToken();
    metadata['auth'] = token ?? '';
  }

  return invoker(
    method,
    request,
    options.mergedWith(CallOptions(providers: [addToken])),
  );
}

natebot13 avatar May 11 '24 04:05 natebot13