Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] grpc/grpc-web backend #504

Closed
borissmidt opened this issue Feb 10, 2022 · 10 comments
Closed

[Feature] grpc/grpc-web backend #504

borissmidt opened this issue Feb 10, 2022 · 10 comments

Comments

@borissmidt
Copy link

Dear stephenh,

For grpc/grpc-web backend there is nice tooling to have better logging of requests in the browser.
But it seems that this project uses typescript grpc-web version.

Which doesn't work for the in browser tooling. Do you have any tips on how to better debug grpc calls in the browser?

Or could the native gprc/grpc-web be used as a backend to get this tooling?

@borissmidt
Copy link
Author

i found out how the plugin works and it is possible to use it like this to get a message in there.
So you just have to wrap the webGrpcImpl and log the incoming and outgoing messages.

//this doesn't work if the reponse is to big
window.postMessage({type: "__GRPCWEB_DEVTOOLS__",method: methodDesc.methodName, methodType: "unary", requestId: requestId, request:_request, response: response})

@stephenh
Copy link
Owner

@borissmidt ah great, that is neat! Thanks for updating that you'd found a solution. I've made a note of it in the readme, to link to this issue.

You're right, ts-proto generates grpc-web code that uses improbable-eng; AFAIU at the time that was added to ts-proto, there was no built-in grpc-web support built into the official grpc.io. It looks like now there is?

Fwiw, if that's the case, and you really want to use the grpc.io packages instead, a PR to add additional support for like --ts_proto_opt=outputClientImpl=grpc-web-on-grpc-io would be great.

Thanks!

(Going to close this out for now since you found your own solution :-).)

@borissmidt
Copy link
Author

Yes, i noticed reading the issues of the official grpc-web that it has issues like memory leaks for long running streams and it does not and will not support websockets. So it seems that the improbable eng implementation is more feature rich. even tough they are not the official one.

@stephenh
Copy link
Owner

Ah huh, that's interesting! Well, I don't feel so bad about ts-proto being "out of date" and not using the latest/official client then. :-)

(Fwiw I don't personally use grpc-web, so I'm reliant on users like yourself to report back/work on/improve the various framework changes / options, like nest/grpc-web/etc. So thanks for the issue!)

@ZholobovSS
Copy link

@borissmidt hello! Can you show full example of how to wrap webGrpcImpl to log messages?

@Swoorup
Copy link

Swoorup commented Nov 6, 2022

Same would like to know, since I can't get it to compile. Where do you add in the hook?

@ZholobovSS
Copy link

ZholobovSS commented Nov 8, 2022

@Swoorup Hi. My typescript solution:

import { GrpcWebImpl, GrpcServiceClientImpl } from 'your/generated/package/here';

export function loggerDecorator(func: GrpcWebImpl['unary']) {
    return async function (...params: Parameters<GrpcWebImpl['unary']>): ReturnType<GrpcWebImpl['unary']> {
        let response: any;

        try {
            //@ts-ignore
            response = await func.apply(this, params);

            return response;
        } catch (error) {
            console.log({ error });
            response = getMessageFromError(error) || 'Ошибка';

            throw new Error(error as any);
        } finally {
            window.postMessage(
                {
                    type: '__GRPCWEB_DEVTOOLS__',
                    method: `${params[0].service.serviceName}/${params[0].methodName}`,
                    methodType: 'unary',
                    request: params[1],
                    response: JSON.parse(JSON.stringify(response)),
                },
                window.location.origin,
            );
        }
    };
}


const rpc = new GrpcWebImpl(REACT_APP_ENVOY_URL, {});

rpc.unary = loggerDecorator(rpc.unary);

export const Clients = {
    serviceClient: new GrpcServiceClientImpl(rpc),
};

@Swoorup
Copy link

Swoorup commented Nov 8, 2022

@ZholobovSS Awesome can confirm that works perfectly. Many thanks

@borissmidt
Copy link
Author

@ZholobovSS Thank you for writing this.

@vshjxyz
Copy link

vshjxyz commented Dec 1, 2023

Hello, I've extended the above to also log streams, as I've noticed that solution was only working for unary calls

import { tap } from "rxjs/operators";

export function loggerDecoratorStream(func: GrpcWebImpl["invoke"]) {
  return function (
    ...params: Parameters<GrpcWebImpl["invoke"]>
  ): ReturnType<GrpcWebImpl["invoke"]> {
    let response: any;

    try {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      //@ts-ignore
      response = func.apply(this, params);

      window.postMessage(
        {
          type: "__GRPCWEB_DEVTOOLS__",
          method: `${params[0].service.serviceName}/${params[0].methodName}`,
          methodType: "server_streaming",
          request: params[1],
        },
        window.location.origin
      );

      return response.pipe(
        tap((data) => {
          console.log("data", data);
          window.postMessage(
            {
              type: "__GRPCWEB_DEVTOOLS__",
              method: `${params[0].service.serviceName}/${params[0].methodName}`,
              methodType: "server_streaming",
              response: JSON.parse(JSON.stringify(data)),
            },
            window.location.origin
          );
        })
      );
    } catch (error) {
      console.log({ error });
      response = error || "error";

      throw new Error(error as any);
    }
  };
}

const rpc = new GrpcWebImpl(REACT_APP_ENVOY_URL, {});

rpc.invoke = loggerDecoratorStream(rpc.invoke);

export const Clients = {
    serviceClient: new GrpcServiceClientImpl(rpc),
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants