add error codes#911
Conversation
| @@ -0,0 +1,28 @@ | |||
| 'use strict' | |||
|
|
|||
| const codes = { | |||
There was a problem hiding this comment.
These should be actual codes, not strings. Look at how core is doing this:
There was a problem hiding this comment.
You mean native Errors objects? This is debatable. We already work with error objects and don't use inheritance.
There was a problem hiding this comment.
No, I mean FST_ERR_FOO should be equal to 42.
There was a problem hiding this comment.
Regardless, the issue is that strings are fragile. Symbols are fine.
There was a problem hiding this comment.
Yep, symbols are unique but can't be converting to strings (logging). Due to the fact that we prefix all strings we can guarantee their uniqueness.
There was a problem hiding this comment.
I think strings are fine, and what Node core is using. I’ll do a more detailed review asap.
There was a problem hiding this comment.
Mistake. Symbols are unique by default (at comparison) with a prefix we only guarantee collision-freedom (at definition). Do you think it will outperform the logging capabilities rather to write tests for that case?
allevo
left a comment
There was a problem hiding this comment.
Nice!
annotateError is used in twice way:
reply.send(annotateError(err, errorCodes.FST_ERR_ON_REQUEST_HOOK))var err = new Error('Unsupported Media Type: ' + contentType); err = annotateError(err, errorCodes.FST_ERR_HTTP)
Can you rewrite using only one way?
|
Hi @allevo I'm using |
|
I am not a fan of the approach of "annotating" extraneous errors with our codes. IMHO we should only be using codes for errors that we create. The code should be included in the error message, similarly to what Node.js does. I'm actually ok in the |
|
Another way could be |
|
Completely agree with @mcollina. Something like the following could be nice. |
|
I will try to meet all requirements:
|
|
Please check current state it's not final just an approach. |
| var result = parser.fn(req, body, done) | ||
| if (result && typeof result.then === 'function') { | ||
| result.then(body => done(null, body)).catch(err => done(err)) | ||
| result.then(body => done(null, body), done) |
There was a problem hiding this comment.
Errors thrown by the done function wont be caught anymore. Is this ok?
There was a problem hiding this comment.
When using promises you can catch errors in two ways:
promise.then(fn).catch(errorHandler)
//or
promise.then(fn, errorHandler)So this is fine :)
https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
There was a problem hiding this comment.
I could be misunderstanding something but the first example will also catch the errors raised by fn whereas the second one wont. Right? It might be that done it is not going to raise any error, and in that case it would be fine.
Promise.resolve(1)
.then(() => { throw new Error('done() error') })
.catch(() => console.log('Caught!')) // Called
Promise.resolve(1)
.then(
() => { throw new Error('done() error') },
() => console.log('Caught!') // Never called
)There was a problem hiding this comment.
@dicearr is right in the theoretical side. However in this case this is not needed. done() is set up to be called in a callback-based scenario. In any case, we can just add in a little try-catch.
Avoiding the .catch() saves us the allocation of one promise.
There was a problem hiding this comment.
Sry, for the late response. What @mcollina said is correct and was my intention.
|
@fastify/fastify please review the way of error handling when it's fine I can continue. |
mcollina
left a comment
There was a problem hiding this comment.
Good job! I think this is a semver-major change.
| if (parser === undefined) { | ||
| reply.code(415).send(new Error('Unsupported Media Type: ' + contentType)) | ||
| var err = new FST_ERR_CTP_INVALID_MEDIA_TYPE(`Unsupported Media Type: ${contentType}`) | ||
| reply.code(415).send(err) |
There was a problem hiding this comment.
Should we include the code in the Error instead?
There was a problem hiding this comment.
You mean err.statusCode = 415 ?
| const errClass = class FastifyError extends Base { | ||
| constructor (...args) { | ||
| super(`Code: ${code}; ${createMessage(args)}`) | ||
| } |
There was a problem hiding this comment.
is this adding another level in the stacktrace? can you please verify and and add a test for that?
There was a problem hiding this comment.
No, the constructor call is omitted. Do you know how to test it reliable?
| t.fail('should throw') | ||
| } catch (err) { | ||
| t.is(err.message, 'The body parser can only parse your data as \'string\' or \'buffer\', you asked \'fireworks\' which is not supported.') | ||
| t.is(err.message, `Code: FST_ERR_CTP_INVALID_PARSE_TYPE; The body parser can only parse your data as 'string' or 'buffer', you asked 'fireworks' which is not supported.`) |
There was a problem hiding this comment.
Can you please follow the node core standard?
There was a problem hiding this comment.
Could you make an example?
| t.fail() | ||
| } catch (err) { | ||
| t.is(err.message, 'The content type should be a string') | ||
| t.is(err.message, 'Code: FST_ERR_CTP_INVALID_TYPE; The content type should be a string') |
There was a problem hiding this comment.
this should also test that the code is correct
| if (contentLength > limit) { | ||
| reply.code(413).send(new Error('Request body is too large')) | ||
| var err = new FST_ERR_CTP_BODY_TOO_LARGE('Request body is too large') | ||
| reply.code(413).send(err) |
| req.removeListener('error', onEnd) | ||
| reply.code(413).send(new Error('Request body is too large')) | ||
| var err = new FST_ERR_CTP_BODY_TOO_LARGE('Request body is too large') | ||
| reply.code(413).send(err) |
| if (!Number.isNaN(contentLength) && receivedLength !== contentLength) { | ||
| reply.code(400).send(new Error('Request body size did not match Content-Length')) | ||
| var contentLenghtErr = new FST_ERR_CTP_INVALID_CONTENT_LENGTH('Request body size did not match Content-Length') | ||
| reply.code(400).send(contentLenghtErr) |
| var parser = this.cache.get(contentType) || this.getParser(contentType) | ||
| if (parser === undefined) { | ||
| reply.code(415).send(new Error('Unsupported Media Type: ' + contentType)) | ||
| var err = new FST_ERR_CTP_INVALID_MEDIA_TYPE(`Unsupported Media Type: ${contentType}`) |
There was a problem hiding this comment.
I think we should move the message to the errors file as well.
There was a problem hiding this comment.
yes, would produce more readable code.
allevo
left a comment
There was a problem hiding this comment.
LGTM.
I don't like const errClass = class FastifyError extends Base {, but nice work!
|
What you don't like exactly? |
Creating different kind of classes at the start up it's strange, but cool: it's Javascript! |
|
This approach is from node core but yes, it's a little getting used to. |
| if (!msg) throw new Error('Fastify error message must not be empty') | ||
|
|
||
| code = code.toUpperCase() | ||
| const errClass = class FastifyError extends Base { |
There was a problem hiding this comment.
can you avoid the const errClass = class FastifyError and just do codes[code] = FastifyError?
There was a problem hiding this comment.
What do you mean? Should I avoid classes?
|
Can you target this against a |
|
Create one forking from master. |
|
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
This is a first draft of introducing error codes to fastify.
TODO
Checklist
npm run testandnpm run benchmark