Comments (8)
@SalimZayCKA, I think this might be a shortcoming of the gRPC-web transport. Most other gRPC clients merge headers and trailers before providing them as "metadata" in an error.
I think you might be able to include headers with an interceptor. It would be nice to fix this - getting good confidence that a change works correctly and does not introduce regressions is not trivial though, since I don't think we have very good test coverage.
from protobuf-ts.
Here's my attempt at the proposed interceptor:
import { RpcError, RpcInterceptor, RpcMetadata } from '@protobuf-ts/runtime-rpc';
const noop = () => {};
function combineRpcMetadata(a: RpcMetadata, b: RpcMetadata): RpcMetadata {
const out = structuredClone(a);
for (const [key, value] of Object.entries(b)) {
const bIsString = typeof value === 'string';
if (out[key]) {
out[key] = typeof out[key] === 'string' ? out[key] : [out[key]];
if (bIsString) {
out[key].push(value)
} else {
out[key].push(...value);
}
} else {
out[key] = bIsString ? value : [...value];
}
}
return out;
}
export const metaInterceptor: RpcInterceptor = {
interceptUnary(next, method, input, options) {
const res = next(method, input, options);
let maybeHeaders: RpcMetadata | undefined;
res.headers.then((h) => {
maybeHeaders = h;
}, noop);
res.then(noop, (e) => {
if (e instanceof RpcError && maybeHeaders && e.meta !== maybeHeaders) {
// Mutate the RpcError's meta field, trailers are appended to headers
e.meta = combineRpcMetadata(maybeHeaders, e.meta);
}
});
return res;
},
};
from protobuf-ts.
The latter part of this discussion might shed some light on this: grpc/grpc-web#736
from protobuf-ts.
@dawsonc623 that discussion seems a bit unrelated to this issue. This issue is asking for the RpcMetadata received in the response headers to be included in the RpcError (which currently only provides the RpcMetadata from the trailers). The issue you linked to is about the "Rich Error Model" which relies on decoding a google.rpc.Status
message from the grpc-status-details-bin
value in RpcMetadata.
If you want to get a decoded google.rpc.Status
it's pretty simple to create your own function for getting it from RpcMetadata
:
import { base64decode } from '@protobuf-ts/runtime';
import { RpcMetadata } from '@protobuf-ts/runtime-rpc';
import { Status } from 'google/rpc/status';
export function richStatusFromRpcMetadata(meta: RpcMetadata): Status | undefined {
const ref = meta['grpc-status-details-bin'];
if (!ref) return;
const b64StatusBin = typeof ref === 'string' ? ref : ref[ref.length - 1];
return Status.fromBinary(base64decode(b64StatusBin));
}
And assuming you're using the "standard error payloads" you can even get their JSON representation from the google.protobuf.Any
values from the google.rpc.Status
's details
:
import { JsonValue, JsonWriteOptions } from '@protobuf-ts/runtime';
import { Any } from 'google/protobuf/any';
import * as standardErrorDetails from 'google/rpc/error_details';
import { Status } from 'google/rpc/status';
const standardTypeRegistry = Object.values(standardErrorDetails) as unknown as NonNullable<JsonWriteOptions['typeRegistry']>;
export function errorDetailsFromStatus(s: Status, options?: JsonWriteOptions): JsonValue[] {
const opts: JsonWriteOptions = { typeRegistry: standardTypeRegistry, ...(options ?? null) };
return s.details.map((any) => Any.toJson(any, opts));
}
from protobuf-ts.
Maybe I am using the library wrong, but in the case of an error I get a rejection with an RPCError
that does not seem to contain this metadata. Perhaps I have misunderstood how to get the metadata in the case of a failure?
from protobuf-ts.
@dawsonc623 are you sure the service is sending grpc-status-details-bin
in its response (headers or trailers)? You could try to use the interceptor I posted above which should combine the headers and trailers into the RpcError
's meta
property. If you still aren't seeing grpc-status-details-bin
in the meta
that would indicate that the service isn't sending it.
You could also open the browser network inspector and see if the response headers include it.
from protobuf-ts.
The header in question is in the response in my network inspector. However, neither the headers
on the failed call nor the meta
on the error include the Grpc-X
headers (three of them come back on the response per the network inspector) at all. I do get the Content-Length
header of 0 in meta
, which I imagine makes sense in the error case. But it seems like not all of that data makes it into the error object, which I (potentially mistakenly) attributed to the limitation in the linked issue (AFAIK grpc-web
is used as the transport level in my code since I use GrpcWebFetchTransport
).
EDIT Apologies, I mixed up calls and was not testing the code that was using the interceptor (I added it to my sign-up routine but was testing my log-in routine). I will be trying again on the right routine shortly and will report back.
from protobuf-ts.
Follow-up: Even with the interceptor (and calling the right client using it) I get the same result as above (perhaps I did test the correct flow and thought I made a mistake). I also added debug logging to the interceptor and confirmed that data never appears in the interceptor's maybeHeaders
.
from protobuf-ts.
Related Issues (20)
- Is this compiling error could be turned off by Typescript or Option in protobuf-ts HOT 2
- 2.9.2 not working with 'exactOptionalPropertyTypes: true' HOT 1
- Release 2.9.3 breaks serialization for me HOT 6
- Generated message classes cannot be subclassed because of missing 'export' HOT 1
- Error decoding from binary: "cant skip wire type 4" HOT 1
- How to debug INVALID_ARGUMENT? HOT 1
- rpcError cannot support Chinese
- [Request] Flag to handle google wrapper types HOT 1
- Vite cannot found module HOT 2
- Invalid typescript in descriptor.ts HOT 2
- Can't retry request after awaiting response HOT 2
- Typesafe API to retrieve enums from strings HOT 4
- `output_javascript` no longer emits `.d.ts` files HOT 6
- Request: Support for moduleResolution "nodenext" and "node16" HOT 2
- Fails to download v27.0-rc1 (which was just released) HOT 7
- invalid url for latest v27.0-rc1 release HOT 1
- Object generated by protobuf-ts seems not support TWO-WAY binding in vue. HOT 5
- Support for WebTransport/HTTP3 HOT 1
- RPC Output Stream drops data if `AsyncIterator` isn't invoked before response is received
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from protobuf-ts.