Would you like to clone this notebook?

When you clone a notebook you are able to make changes without affecting the original notebook.

Cancel

Endpoint Error Handling Example

node v4.9.1
version: master
endpointsharetweet
This is an example showing a bug in RunKit's error handling for endpoints. Specifically, while RunKit's use of Domains [0] is able to catch errors thrown directly by the exports.endpoint(req, res) function [1], RunKit is unable to catch errors thrown asynchronously [2]. This is not a language limitation, it's straightforward to manually use a Domain to catch the error [3], and RunKit should be doing exactly that. [0]: https://nodejs.org/api/domain.html [1]: https://runkit.io/laughinghan/58337152a62a08001304609a/branches/master/good_caught_error (you can see the use of a Domain in the stacktrace) [2]: https://runkit.io/laughinghan/58337152a62a08001304609a/branches/master/uncaught_error [3]: https://runkit.io/laughinghan/58337152a62a08001304609a/branches/master/manually_caught_error (The full workaround is slightly less straightforward, see the code for the full workaround including an edge case with an event handler and non-empty POST requests.)
const domain = require('domain') exports.endpoint = (req, res) => { const path = req.url.slice(process.env.RUNKIT_MOUNT_PATH.length) if (path === '/good_caught_error') { fail } else if (path === '/uncaught_error') { endpoint(req, res) } else if (path === '/manually_caught_error') { domain.create() .on('error', function (e) { res.statusCode = 500 res.end(`Manually caught error:\n${e.stack}\n`) }) .run(endpoint, req, res) } else if (path === '/surprising_caught_error') { domain.create() .on('error', function (e) { res.statusCode = 500 res.end(`Manually caught error:\n${e.stack}\n`) }) .run(() => fail) } else if (path === '/unable_to_catch_error_if_nonempty_POST') { // this fails if and only if a non-empty POST is submitted to it: // curl -i -X POST https://runkit.io/laughinghan/58337152a62a08001304609a/branches/master/unable_to_catch_error_if_nonempty_POST -d body // GET or empty POST works fine, weirdly enough domain.create() .on('error', function (e) { res.statusCode = 500 res.end(`Manually caught error in event handler:\n${e.stack}\n`) }) .run(() => { req.on('end', () => fail) req.resume() }) } else if (path === '/manually_caught_error_in_event_handler') { const d = domain.create() d.on('error', function (e) { res.statusCode = 500 res.end(`Manually caught error in event handler:\n${e.stack}\n`) }) d.add(req) // this and d.add(res) // this are added to fix the /unable_to_catch_error_if_nonempty_POST edge case d.run(() => { req.on('end', () => fail) req.resume() }) } else { res.setHeader('Content-Type', 'text/html') res.end(`Please go to <a href="${process.env.RUNKIT_MOUNT_PATH}/good_caught_error">/good_caught_error</a>, <a href="${process.env.RUNKIT_MOUNT_PATH}/uncaught_error">/uncaught_error</a>, or <a href="${process.env.RUNKIT_MOUNT_PATH}/manually_caught_error">/manually_caught_error</a>`) } } function endpoint(req, res) { process.nextTick(() => fail) }
Loading…

no comments

    sign in to comment