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

Missing grpc-status in onTrailer metadata

Open polRk opened this issue 10 months ago • 8 comments

https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md

polRk avatar Apr 03 '25 14:04 polRk

The provided document does not state that grpc-status must be present in gRPC trailer. It describes the way it is passed through HTTP2 header or trailer. In nice-grpc the status is manifested on a different level — via ClientError.code property.

aikoven avatar Apr 03 '25 20:04 aikoven

via ClientError.code property.

This is a bit inconvenient, you need to write a lot of code when you could just read it in onTrailer. Do you think we can add this functionality?

polRk avatar Apr 04 '25 07:04 polRk

Can you please provide an example of when it is more convenient to use the trailer than the exception?

aikoven avatar Apr 04 '25 08:04 aikoven

Without


	#debug: ClientMiddleware<ConnectionCallOptions> = async function* (this: Connection, call, options) {
		try {
			if (!call.responseStream) {
				const response = yield* call.next(call.request, options);

				return response;
			} else {
				for await (const response of call.next(call.request, options)) {
					yield response;
				}

				return;
			}
		} catch (error) {
			if (error instanceof ClientError) {
				dbg.extend("grpc")('%s%s', this.address, error.message);
			}

			throw error;
		}
	}

With:

	#debug: ClientMiddleware<ConnectionCallOptions> = async function* (this: Connection, call, options) {
		return yield* call.next(call.request, {
			...options,
			onTrailer: (trailer) => {
				dbg.extend("conn")('node id=%d address=%s status=%o', this.nodeId, this.address, trailer.get('grpc-status'));
			},
		})
	}

polRk avatar Apr 04 '25 11:04 polRk

This makes sense, but according to this doc the grpc-* headers are internal and are not exposed in gRPC metadata.

By the way, your example can be made shorter:

	#debug: ClientMiddleware<ConnectionCallOptions> = async function* (this: Connection, call, options) {
		try {
			return yield* call.next(call.request, options);
		} catch (error) {
			if (error instanceof ClientError) {
				dbg.extend("grpc")('%s%s', this.address, error.message);
			}

			throw error;
		}
	}

aikoven avatar Apr 04 '25 20:04 aikoven

and are not exposed in gRPC metadata.

Some gRPC implementations expose grpc-*

polRk avatar Apr 05 '25 07:04 polRk

Can you give examples of that?

aikoven avatar Apr 06 '25 10:04 aikoven

https://github.com/connectrpc/connect-es https://www.npmjs.com/package/@connectrpc/connect

polRk avatar Apr 06 '25 13:04 polRk