Skip to content

add isFastifyError#86

Closed
Uzlopak wants to merge 3 commits into
masterfrom
isFastifyError
Closed

add isFastifyError#86
Uzlopak wants to merge 3 commits into
masterfrom
isFastifyError

Conversation

@Uzlopak

@Uzlopak Uzlopak commented Nov 2, 2022

Copy link
Copy Markdown
Contributor

Closes #17

Checklist

@Uzlopak
Uzlopak requested a review from jsumners November 2, 2022 12:09
Comment thread index.js Outdated
@Uzlopak

Uzlopak commented Nov 2, 2022

Copy link
Copy Markdown
Contributor Author

@jsumners

Should i change

FastifyError.prototype[Symbol.toStringTag] = 'Error'

to

FastifyError.prototype[Symbol.toStringTag] = 'FastifyError'

?

@Uzlopak

Uzlopak commented Nov 2, 2022

Copy link
Copy Markdown
Contributor Author

I guess that is what you want.

Probably should be then a semver major.

Comment thread index.js
this.statusCode = statusCode || undefined
}
FastifyError.prototype[Symbol.toStringTag] = 'Error'
FastifyError.prototype[Symbol.toStringTag] = 'FastifyError'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially breaking change and should result in a major versoin bump

@Uzlopak
Uzlopak requested review from Eomm and mcollina November 2, 2022 12:22
Comment thread index.js
}

function isFastifyError (value) {
return Object.prototype.toString.call(value) === '[object FastifyError]'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hardly -1 on this approach.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcollina I believe you want to say: "I'm strongly -1". Saying "I'm hardly" means "I'm in favor of this".

What is your disagreement with this? An instanceof check would break if someone is using their own import of fastify-error to check an error generated by Fastify's internal import of fastify-error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcollina @jsumners suggested this approach. What should we agree on?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it work with a custom symbol?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the toStringTag is a spec defined symbol.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just set our custom
Symbol for every instance created by the constructor and check for it. We already do this in our codebase.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. But we are delving deeper into hack territory.

@Uzlopak

Uzlopak commented Nov 2, 2022

Copy link
Copy Markdown
Contributor Author

What about the classic?

function isFastifyError (value) {
  return (
    typeof value === 'object' &&
    value !== null &&
    value.name === 'FastifyError'
  )
}

I mean... if somebody changes the name of the error it is basically saying it is not a FastifyError anymore. Like we change the name from Error to FastifyError to indicate we have our own Error Class.

@mcollina

mcollina commented Nov 2, 2022

Copy link
Copy Markdown
Member

Going back to the original issue: what problem are we trying to solve for here? What usage do we want? I do not see a good case to use that method that's not a code smell. At this point instanceof does not worsen the coupling.

The fact that the whole Fastify ecosystem could be built without this existing should tell something.

@jsumners

jsumners commented Nov 2, 2022

Copy link
Copy Markdown
Member

Going back to the original issue: what problem are we trying to solve for here?

🤷‍♂️ I only have the recommendation to prevent "not an instance of" errors.

@mcollina

mcollina commented Nov 2, 2022

Copy link
Copy Markdown
Member

My best recommendation would be to have a utility to check if it has a code and/or statusCode set.

@Uzlopak

Uzlopak commented Nov 2, 2022

Copy link
Copy Markdown
Contributor Author

The question is if we should instead improve the documentation what we consider best practise and about ducktyping FastifyError.

I could do that instead, if we agree on

Comment thread index.js
}

function isFastifyError (value) {
return Object.prototype.toString.call(value) === '[object FastifyError]'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it work with a custom symbol?

Comment thread test/index.test.js
t.plan(8)

const NewError = createError('CODE', 'Not available')
t.equal(isFastifyError(NewError()), true)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should consider the createError instances as "application error" instead of Fastify Error

@fox1t

fox1t commented Nov 2, 2022

Copy link
Copy Markdown
Member

This is easy as adding a custom unique symbol to every instance created by the constructor and then checking for it inside the isFasitfyError function.
@mcollina having this function will allow the users to easier check inside the error handlers if it is an application-level error or an unexpected unhandled error.

@Uzlopak

Uzlopak commented Nov 2, 2022

Copy link
Copy Markdown
Contributor Author

I guess you could do

const kFastifyError = Symbol.for('FastifyError')

And add it like we do with toStringTag.

@mcollina

mcollina commented Nov 2, 2022

Copy link
Copy Markdown
Member

@mcollina having this function will allow the users to easier check inside the error handlers if it is an application-level error or an unexpected unhandled error.

I typically use this module for my applications too.

The only way to know if an error comes from Fastify is to check the prefix of the code property.

@jsumners

jsumners commented Nov 2, 2022

Copy link
Copy Markdown
Member

@mcollina having this function will allow the users to easier check inside the error handlers if it is an application-level error or an unexpected unhandled error.

I typically use this module for my applications too.

The only way to know if an error comes from Fastify is to check the prefix of the code property.

So your objection is the object name?

@mcollina

mcollina commented Nov 2, 2022

Copy link
Copy Markdown
Member

My objection is on how this is supposed to be used. I would instanceof individual errors, but not a blanket check against all the errors this module can produce.

If somebody wants all Fastify core errors, they can do err.code?.indexOf('FST_') === 0.

@jsumners

jsumners commented Nov 2, 2022

Copy link
Copy Markdown
Member

I would instanceof individual errors

This is not reliable. See the attached example. Within it is an example/00_main/index.js that imports some dependent library example/01_dependency/ that looks like:

'use strict'

const VError = require('verror') 
const foo = require('foo')

try {
  foo()
} catch (error) {
  console.log(error instanceof VError)
}

const error = VError('not foo')
console.log(error instanceof VError)

This example will output the following:

$ node 00_main/index.js
false
true

Notice that both the "main" application and the dependency rely on the exact same version of verror. In order for instanceof to work in this case, the 01_dependency would need to export its instance of VError so that 00_main could use it.

If verror were to implement [Symbol.toStringTag], the proposal in this PR would fix the issue.

example.zip

@fox1t

fox1t commented Nov 3, 2022

Copy link
Copy Markdown
Member

My objection is on how this is supposed to be used. I would instanceof individual errors, but not a blanket check against all the errors this module can produce.

If somebody wants all Fastify core errors, they can do err.code?.indexOf('FST_') === 0.

I agree with this. This proposal is also about knowing if the error is a fastifyError, regardless if Fastify, a plugin, or user code threw it. You are right, though, when you say that it is achievable checking for code and statusCode. I was thinking about providing a utility that can lower the barrier for the developers. I saw that error handling is usually one of the worst parts of the applications, and one of the barriers is handling application errors vs. unexpected errors. Boom has isBoom to allow the users check the error inside errorHandlers and act accordingly.

Hope this makes sense.

@Uzlopak

Uzlopak commented Nov 3, 2022

Copy link
Copy Markdown
Contributor Author

Also dont forget jest. It messes also instanceof Error up.

Maybe we should find a solution based on Symbol.hasInstance?

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance

@mcollina

mcollina commented Nov 4, 2022

Copy link
Copy Markdown
Member

Here is my taken on how I would implement this for Fastify:

if (err.code.indexOf('FST_') === 0) {
  // All Fastify errors go there.
}

@jsumners

jsumners commented Nov 5, 2022

Copy link
Copy Markdown
Member

How would that solve the generic usage case of this module? I think the module name is confusing the goal. As I understand the desire, it is to determine if an error instance has been created by this module. Not necessarily that an error instance is one from the Fastify framework.

@mcollina

mcollina commented Nov 5, 2022

Copy link
Copy Markdown
Member
  1. I think the name of the module is incorrect in that sense as it has nothing to do with Fastify, but rather it's something we maintain.

  2. I don't see the reason to test if an error has been generated by this module. Why would you do it?

  3. I can see the reason to check if an error has code and statusCode properties set to meaningful values.

@fox1t

fox1t commented Nov 5, 2022

Copy link
Copy Markdown
Member

@mcollina,, checking if an error is a fastify error could allow the users to know if the error is an application logic error (fastifyError) or any other unhandled error. This information will enable the users to act accordingly: send a report to external tools, set proper code for the response, etc. Basically, the ordinary operations that we all usually do inside error handlers.

@Uzlopak

Uzlopak commented Nov 5, 2022

Copy link
Copy Markdown
Contributor Author

@fox1t
Repeating the same argument over and over does not make it more convincible.

@mcollina

mcollina commented Nov 5, 2022

Copy link
Copy Markdown
Member

@fox1t the solution described in #86 (comment) is perfect for that use case as it uses error codes.

@fox1t

fox1t commented Nov 5, 2022

Copy link
Copy Markdown
Member

@fox1t
Repeating the same argument over and over does not make it more convincible.

Pardon me? I was making the same point @jsumners made since I had the same impression that not everyone was on the same page. I don't have to convince anyone. Since I proposed this in the first place I tried to make sure that everyone understands what I am proposing.
@mcollina I agree with you. Here we are discussing if shipping a helper function could help the newcomers understand how to use this library as a generic error library instead of giving the impression it can be used only for Fastift core or Fastify plugins ecosystem. Since the error format is the same as I used in Interference and since we discussed the error format together a while ago, I think that this library can provide value outside of the Fastify ecosystem.

@xtx1130 xtx1130 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is a good case in https://github.com/hapijs/boom/blob/master/lib/index.js#L92-L108. Both using Symbol.hasInstance and special parameters to judge an instance

Comment thread README.md

#### isFastifyError

The module exports a isFastifyError-function that you can use to check if a value is of type FastifyError, it takes one parameters:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The module exports a isFastifyError-function that you can use to check if a value is of type FastifyError, it takes one parameters:
The module exports a isFastifyError-function that you can use to check if a value is of type FastifyError, it takes one parameter:

@Uzlopak

Uzlopak commented Sep 1, 2023

Copy link
Copy Markdown
Contributor Author

Closing due to inactivity (lol)

@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

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.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators May 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

should this package expose FastifyError?

6 participants