Open philectron opened 4 years ago
I think it would be worthwhile looking into a refactor that is inline with this suggestion, something that might be easier to discuss today in person after our client meeting.
In the above example I wonder if the // check if the provided userId in the route is a positive integer
step should be handled by the schema. In general I think it may make sense for the schema validation to happen before any other forms of validation.
I like the idea of avoiding indentation issues by using middleware in general. I don't think this is an issue or a conflict, but I would like to clarify the basic structure I expect from an endpoint just so we can make sure we are on the same page or find a middle ground:
Note: Depending on the endpoint step 2 or 3 may not come into play. We may not need step 2 for an endpoint that doesn't have params or a body. Likewise we may not need 3 for a endpoint that anyone can use and is so simple that it doesn't have any constraints.
The Problem
I usually see the following pattern in the API route handlers:
I have thought about returning early in the middleware function to avoid nested
if-else
andtry-catch
blocks, but there are things that still bug me, such as thatreturn
in a middleware function will produce any side-effects.Proposed Solution
For these reasons, I think it'd be better to utilize
next()
and/or put additional middleware functions in between to handle various errors (like shown in Express's error handling guide). If Express offers us ways to handle errors while processing requests, we should use them.What It Will Look Like
If we agree on how we should refactor these error handling steps, I think our refactored handlers will look like this (take
PATCH /user/:userId
as an example) (refer to this page for the syntax):What It Will Improve
This solution separates the API route handling process into multiple parts, each of which concerns itself with only what it's supposed to do: auth checking, role checking, request validation, etc., and then the main logic at the end. As a result, the main logic is less indented and thus more readable and maintainable.
Furthermore, since we repeatedly role-check the authenticated user, we can easily put the role-checking code into a function (just like
requireAuth
) and pass it into this route handler, but that's another refactor for another time--I'm just showing the flexibility of this solution.