-
Notifications
You must be signed in to change notification settings - Fork 5.2k
isClientSafe DDP errors #8756
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
isClientSafe DDP errors #8756
Conversation
I think a similar thing would be useful for GraphQL as well, do we think it might be nice to promote isClientSafe? Might it be better instead of a flag to maybe have a version of the error that is client safe, as a field on the error object? Like it would have validation information but maybe not stack traces? |
@stubailo, I think that might be a good idea, it gives the package maintainers more control of the shape of the exception that would be forwarded to the client. But, doesn't the forwarded error need to be an instance of |
On the wire, it's just a JSON blob - so the client can make that into a
We can promote this mechanism in the Apollo |
@stubailo I'm happy to adjust to whatever implementation people want. Just wanted to get something up. My only priority is removing the need for any dependencies, and still being able to pass back additional error details JSON, which SimpleSchema currently does using the The "To specify an error that is safe to be sent back to the remote caller, set It could then attempt to generically serialize the error (standard error props + "own" props) rather than explicitly looking for "reason", "details", etc. Let me know what you all are thinking, and I can update the PR. I just don't know how deep into the DDP spec I should make changes. It should definitely be possible to remove all As an aside, mdg:validation-error could also be ported to an npm package following this new spec. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some discussion this morning in our triage meeting, I'm a fan of the isClientSafe
property as a convention that can be respected by multiple interacting libraries/frameworks, given the limitations of instanceof
when you don't have access to the constructor function.
To move forward with this PR:
- The
Meteor.Error
constructor should setthis.isClientSafe = true
, so that allMeteor.Error
objects pass either test. This should also give ussanitizedError.isClientSafe
for free. - We should replace all
error instanceof Meteor.Error
checks witherror && error.isClientSafe
. - The current implementation needs to change a bit to prevent accidentally wrapping
Meteor.Error
objects with newMeteor.Error
objects.
With those issues addressed, I like this idea a lot!
Thanks @benjamn, I'll work on those changes this weekend. |
@benjamn I made the requested changes. You said to replace |
if (exception.isClientSafe) { | ||
if (!(exception instanceof Meteor.Error)) { | ||
const originalMessage = exception.message; | ||
exception = new Meteor.Error(exception.error, exception.reason, exception.details); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that these properties (exception.error, exception.reason, exception.details
) will be defined (or safely undefined) for arbitrary exception
objects that happen to use the exception.isClientSafe
convention? Should Meteor.Error
take in the whole exception
object and copy its properties (e.g. .stack
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in Meteor.Error
constructor, it would if (error instanceof Error)
then copy all "own" props plus message and stack to self?
I like that idea in general, but as I look at this a bit more, I'm not sure that casting to Meteor.Error
here is actually necessary. Whatever this function returns is set to the error
prop on the DDP payload, and stringifyDDP
seems to just clone and send it. addType
is not even used for Meteor.Error
for EJSON, so it might just work with any error already?
However, I think the client does assume there will be error, reason, and details props in reconstructing the error on the other end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relevant comment from errors.js:
// Note: The DDP server assumes that Meteor.Error EJSON-serializes as an object
// containing 'error' and optionally 'reason' and 'details'.
// The DDP client manually puts these into Meteor.Error objects. (We don't use
// EJSON.addType here because the type is determined by location in the
// protocol, not text on the wire.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reconstruction on client would also need to do a more generic copying of properties I think. In livedata_connection.js:
if (_.has(msg, 'error')) {
m.receiveResult(new Meteor.Error(
msg.error.error, msg.error.reason,
msg.error.details));
} else {
// msg.result may be undefined if the method didn't return a
// value
m.receiveResult(undefined, msg.result);
}
@@ -1736,10 +1747,10 @@ var wrapInternalException = function (exception, context) { | |||
// provided a "sanitized" version with more context than 500 Internal server | |||
// error? Use that. | |||
if (exception.sanitizedError) { | |||
if (exception.sanitizedError instanceof Meteor.Error) | |||
if (exception.sanitizedError.isClientSafe) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To your question, I think just checking .isClientSafe
(without also checking instanceof Meteor.Error
) is fine, now that all Meteor.Error
objects will have .isClientSafe
set to true
.
We will be bumping at least the minor version of both packages in Meteor 1.5.1, so they should both be forced to update by the Meteor release. Note: we're only bumping the patch version of |
This is a possible implementation of something we discussed about a year ago here: https://forums.meteor.com/t/meteor-guide-methods/19662/34?u=aldeed
If any thrown error has
isClientSafe
set totrue
, it is cast into aMeteor.Error
to be sent back to the client. I think an ideal implementation would not even referenceMeteor.Error
anywhere in the DDP code, but this is a simple, safe, backwards compatible solution for now.The goal here is for NPM packages like simpl-schema to be able to throw validation or other errors and have them sent back to the client call.
One question: Should it do the same thing for any sanitizedError that has
isClientSafe
set?Closes #7305