Reputation: 13532
I am using callbacks with socket.io
Client code :
socket.emit('someEvent', {data:1}, function(err, result) {
console.log(err.message);
});
Server code :
socket.on('someEvent', function(data, callback) {
callback(new Error('testing error'));
});
With the above code the client side always prints out undefined
. If I change the server side code to the following I can see the error message.
socket.on('someEvent', function(data, callback) {
callback({message:'testing error'});
});
I can pass my own custom objects to the client just fine, just not the error object. Any ideas?
Upvotes: 13
Views: 8948
Reputation: 3444
Here's a little router function that works with plain error objects. You might want to remove the stack variable if you're shy.
socket.on('api', async (method, args, callback) {
try {
const result = await api[method](...args)
callback(null, result)
} catch (error) {
const { name, message, stack } = error
callback(error.toJSON ? error : { name, message, stack })
}
})
Upvotes: 0
Reputation: 6884
I also think it's odd that Socket.IO doesn't seem to provide explicit built in support for passing Error objects in a meaningful way.
If you want to have Error objects seralized correctly in Socket.IO callbacks you can define a method like this to specify how serialization with .toJSON
for Error messages should be handled:
if (!('toJSON' in Error.prototype)) {
Object.defineProperty(Error.prototype, 'toJSON', {
value: function () {
let result = {}
Object.getOwnPropertyNames(this).forEach((key) => {
if (key === 'stack') return
result[key] = this[key];
}, this)
return result
},
configurable: true,
writable: true
})
}
If you are throwing messages from the server you will want to define this on the server, and if throwing errors from a client to the server you will need to define it on the client too.
Note: In this example it strips the 'stack' property when returning errors to the client (to avoid exposing internals to a client), but this may be something worth leaving in, at least for development mode.
Adapted from a blog post I wrote recently on this:
https://medium.com/@iaincollins/error-handling-in-javascript-a6172ccdf9af
I'm happy to say this easier/cleaner with ES6.
If you define your class extending Error like this:
class ValidationError extends Error {
constructor(message) {
super(message)
this.name = 'ValidationError'
this.message = message
}
toJSON() {
return {
error: {
name: this.name,
message: this.message,
stacktrace: this.stack
}
}
}
}
Instead of this being the object that gets passed back:
{ name: 'ValidationError' }
It now looks something like this:
{
error: {
name: 'ValidationError',
message: 'A validation error',
stacktrace: '…'
}
}
You can see what to expect by doing this:
console.log(JSON.stringify(new ValidationError('A validation error'))
Upvotes: 1
Reputation: 161457
socket.io
data is serialized as JSON
, which can only represent plain objects. You will need to serialize any errors into a recognizable plain-object format, or let Socket.IO's standard serialization do its thing (which will result in a plain empty object for Error
instances.
Upvotes: 14