Skip to content
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

feat: Improve error experience #2954

Merged
merged 18 commits into from
May 1, 2021

Conversation

metcoder95
Copy link
Member

@metcoder95 metcoder95 commented Mar 24, 2021

Fixes #2842

This PR tries to improve the error experience by changing to sync registering of routes along with a new error object for Fastify errors.

Checklist

Base automatically changed from master to main March 26, 2021 12:02
@metcoder95 metcoder95 marked this pull request as ready for review March 29, 2021 21:44
@@ -502,6 +502,9 @@ function fastify (options) {
} else if (name === 'onReady') {
this[kHooks].validate(name, fn)
this[kHooks].add(name, fn)
} else if (name === 'onRoute') {
Copy link
Member Author

Choose a reason for hiding this comment

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

I need to move the setup for the onRoute hooks due to the fact that was made for being async, in order to achieve register routes sync, the hooks should also be set in the same way. Please let me know your thoughts

lib/route.js Outdated Show resolved Hide resolved
test/hooks.test.js Outdated Show resolved Hide resolved
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

Can you please target next instead?

lib/route.js Show resolved Hide resolved
lib/route.js Outdated Show resolved Hide resolved
test/hooks.test.js Outdated Show resolved Hide resolved
@mcollina mcollina added this to the v4.0.0 milestone Mar 30, 2021
@mcollina mcollina added the v4.x Issue or pr related to Fastify v4 label Mar 30, 2021
@jsumners
Copy link
Member

The description as I write this is "WIP". Therefore, I am marking it as a draft. Please mark it ready for review when you feel it is ready.

@jsumners jsumners marked this pull request as draft March 31, 2021 12:11
@metcoder95 metcoder95 force-pushed the improve_error_experience branch 2 times, most recently from 3ae7553 to c26bd0e Compare April 1, 2021 20:05
@metcoder95 metcoder95 changed the base branch from main to next April 1, 2021 20:11
@metcoder95 metcoder95 force-pushed the improve_error_experience branch 2 times, most recently from f9c50f2 to 4b313e1 Compare April 1, 2021 21:35
@metcoder95 metcoder95 marked this pull request as ready for review April 6, 2021 21:09
@metcoder95 metcoder95 requested a review from mcollina April 6, 2021 21:13
lib/route.js Outdated
Comment on lines 262 to 246
// There's a bug when ignoreTrailingSlash !== true
// See
/*
└── /prefix
└── / (GET)
/ (HEAD)
└── / (GET)
**/
Copy link
Member Author

Choose a reason for hiding this comment

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

This is a pretty interesting error popping up only when ignoreTrailingSlash === true, I didn't dig deep too much but was quite hard to detect. The third route comes out nowhere and the call stack is not really descriptive. I can take a look into it but not sure if it belongs directly to this PR as it happens before targeting to next branch.

Copy link
Member

Choose a reason for hiding this comment

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

I don't understand the error you are describing. As it happens on master as well, open a fresh issue.

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure if it happens on main but caused me problems when pointing to next.
What it does is create a third route out of nowhere, as described in the comment. A third route under /prefix// is made, only if ignoreTrailingSlash = true. I'll try to see if I can reproduce it on main

Copy link
Member

Choose a reason for hiding this comment

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

It happens in next without this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

Incredibly I was not able to reproduce it on next after a rebase. I'll try to figure out if stills reproducible or maybe was part of my changes before getting it stable

@@ -173,7 +173,7 @@ test('route', t => {
test('invalid schema - route', t => {
t.plan(3)

const fastify = Fastify()
const fastify = Fastify({ exposeHeadRoutes: false })
Copy link
Member Author

Choose a reason for hiding this comment

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

I set exposeHeadRoutes to false in order to let the test pass with the correct route, as now if there's a schema validation error, the HEAD route validation is being thrown first, just before the origin GET route

Copy link
Member

Choose a reason for hiding this comment

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

Have you rebased this PR on top of next? I think I fixed this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, actually rebasing to next popped up the issue. The routes are registered in order, first GET and HEAD as second, but as the schema build happens async, the first that comes up is always for the HEAD one

Copy link
Member

Choose a reason for hiding this comment

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

I have a feeling that we should fix this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I found the issue, basically in order to receive first the error thrown by the schema validation of the first GET route, is a need to pass the error to the done function when receiving the error from the schema validation. Solved on 1ac09cc

test/404s.test.js Show resolved Hide resolved
@@ -173,7 +173,7 @@ test('route', t => {
test('invalid schema - route', t => {
t.plan(3)

const fastify = Fastify()
const fastify = Fastify({ exposeHeadRoutes: false })
Copy link
Member

Choose a reason for hiding this comment

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

Have you rebased this PR on top of next? I think I fixed this.

@@ -170,7 +170,7 @@ test('Cannot add schema for query and querystring', t => {

test('Should throw of the schema does not exists in input', t => {
t.plan(2)
const fastify = Fastify()
const fastify = Fastify({ exposeHeadRoutes: false })
Copy link
Member

Choose a reason for hiding this comment

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

what happens if this is set to true?

Copy link
Member Author

Choose a reason for hiding this comment

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

The error validates a throw on an unexisting schema reference, but the test is waiting for the error to be thrown on the original GET /:id endpoint. But because of the order of the routes being loaded (first GET , second HEAD), the validation always fails on the HEAD route throwing exactly the same error but just for the sibling route

Copy link
Member

Choose a reason for hiding this comment

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

Can you add a test with exposeHeadRoutes: true?

test/throw.test.js Show resolved Hide resolved
lib/route.js Outdated
Comment on lines 262 to 246
// There's a bug when ignoreTrailingSlash !== true
// See
/*
└── /prefix
└── / (GET)
/ (HEAD)
└── / (GET)
**/
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand the error you are describing. As it happens on master as well, open a fresh issue.

test/hooks.test.js Outdated Show resolved Hide resolved
test/throw.test.js Outdated Show resolved Hide resolved
test/hooks.test.js Show resolved Hide resolved
@metcoder95
Copy link
Member Author

metcoder95 commented Apr 13, 2021

There was a recent update that changed the behavior of fast-json-stringify?

It's not because of that, basically on route.js the compileSchemasForSerialization is throwing twice being only the last one captured by avvio, the first one is the one expected from the test but not being able to achieve it

Basically, the same as the previous bugs. The sibling HEAD route is throwing the correct error, meanwhile the original GET one is throwing the new error showed below 😅

The tests is receiving a new error:

-Failed building the serialization schema for GET: /:id, due to error Cannot read property 'type' of undefined
          
+Failed building the serialization schema for GET: /:id, due to error schema is invalid: data.properties['name'] should be object,boolean

Comment on lines +344 to +330
const { exposeHeadRoute } = opts
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes

if (shouldExposeHead && options.method === 'GET' && !headRouteExists) {
const onSendHandlers = parseHeadOnSendHandlers(opts.onSend)
prepareRoute.call(this, 'HEAD', path, { ...opts, onSend: onSendHandlers })
} else if (headRouteExists && exposeHeadRoute) {
warning.emit('FSTDEP007')
Copy link
Member Author

Choose a reason for hiding this comment

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

The error stated on this comment was caused by the order of how the sibling HEAD route was being registered for each GET one.

As each GET route was creating the sibling HEAD one before registering a handler for the after hook, the HEAD route was registering first the hook handler, changing the order on how the validations should be done.

I moved the register of the sibling route on the after route hook. Not sure if is the best or should do it after registering the hook handler and not within. Looking forward to having feedback 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Good for me

lib/route.js Outdated Show resolved Hide resolved
lib/route.js Show resolved Hide resolved
fastify.listen(0, err => {
t.ok(err)
})
t.fail('setNotFoundHandler should not interfer duplicated route error')
Copy link
Member

Choose a reason for hiding this comment

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

"interfer" is not a word I recognize.

Copy link
Member Author

Choose a reason for hiding this comment

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

This one and here solved in 5bfeeb 👍

Copy link
Member

Choose a reason for hiding this comment

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

I'm still seeing this on GitHub.

Copy link
Member Author

Choose a reason for hiding this comment

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

I made another typo, sorry 😓
Done in 0659eb5

@@ -170,7 +170,7 @@ test('Cannot add schema for query and querystring', t => {

test('Should throw of the schema does not exists in input', t => {
t.plan(2)
const fastify = Fastify()
const fastify = Fastify({ exposeHeadRoutes: true })
Copy link
Member

Choose a reason for hiding this comment

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

it is exposeHeadRoutes is true by default.

Suggested change
const fastify = Fastify({ exposeHeadRoutes: true })
const fastify = Fastify()

Copy link
Member Author

Choose a reason for hiding this comment

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

Done in 0659eb5

Copy link
Member

@RafaelGSS RafaelGSS left a comment

Choose a reason for hiding this comment

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

Can you add a new test to not call onRoute twice when duplicate routes?

lib/route.js Outdated Show resolved Hide resolved
lib/route.js Outdated
Comment on lines 262 to 246
// There's a bug when ignoreTrailingSlash !== true
// See
/*
└── /prefix
└── / (GET)
/ (HEAD)
└── / (GET)
**/
Copy link
Member

Choose a reason for hiding this comment

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

It happens in next without this PR?

lib/route.js Outdated Show resolved Hide resolved
lib/route.js Show resolved Hide resolved
@metcoder95
Copy link
Member Author

Personally, I'm ok with the current approach, I don't see any cases that call onRoute twice on a duplicate route would be bad or dangerous. However, the current documentation says:

OnRoute
Triggered when a new route is registered here

Perhaps, I'd just change to "Triggered before a new route is registered" just to avoid confusion. What do you all think of that?

Sure, sounds good to me, has more sense as is indeed triggered before registering the route rather than after it. Let me update the documentation about it 👍

can you merge/rebase on top of next? I've merged master in next.
Done, is passing now!

@metcoder95
Copy link
Member Author

I added the changes for the documentation and remove the comments on the code, feel free to take another look and share feedback 🙂

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm

Copy link
Member

@RafaelGSS RafaelGSS left a comment

Choose a reason for hiding this comment

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

LGTM.

@mcollina
Copy link
Member

Any more feedbacks on this? @delvedor @jsumners @fastify/core?

Copy link
Member

@jsumners jsumners left a comment

Choose a reason for hiding this comment

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

LGTM

@mcollina mcollina merged commit a36f6f3 into fastify:next May 1, 2021
@metcoder95 metcoder95 deleted the improve_error_experience branch May 11, 2021 20:34
@github-actions
Copy link

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 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
v4.x Issue or pr related to Fastify v4
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve errors user experience
4 participants