In what layer does request validation go in a Node REST API?
In a Node REST API, there are multiple different layers where you could conceivably put request validation, the code where you verify that the request is "valid" and has the correct fields, checks that those fields are the expected types, etc.
In a layered API that roughly follows a web tier, service tier, and data tier structure, it makes more sense to do the request validation in the web tier, since it is the one that deals with the HTTP request. If the request is invalid, it doesn't make sense to call all the other layers of code. (Note: typically you will have some kind of model or query validation "further down" the stack, but that is a different type of validation than what we're talking about here.)
But the web tier is made up of middleware and controllers/router handlers. Which of these should you put your request validation in? With all the different types of logic in a REST API, knowing what code goes where can be confusing with lots of conflicting information out there.
For a recap on the difference between middleware and controllers, check out this post.
Best place
I think the conclusive place to put request validation is in the middleware. You usually want to bail as early as possible if you are dealing with an invalid request, as opposed to letting code seep "further down" to execute. Controllers/route handlers are closest to middleware - so it may not seem like a big deal to do the validation there - but it's still "one layer" deeper than just bailing early from the middleware.
You also keep your controllers thinner and cleaner by keeping request validation out of them, and you end up having better separation of concerns. Middleware is responsible for the validation, and controllers are responsible for routing the request where it needs to go after it's been validated.
You can also better reuse the validation logic in other routes if it's separated into middleware rather than baked into a controller.
Below is pseudo-code for what this would look like:
const app = express()
// the schema to use for validating the request
const orderSchema = {
type: 'object',
required: ['total', 'items'],
properties: {
total: {
type: 'number',
minimum: 0.5,
},
items: {
type: 'array',
uniqueItems: true,
items: {
type: 'object',
properties: {
itemId: {
type: 'integer'
},
quantity: {
type: 'integer'
}
}
}
}
}
};
app.post(
'/order', // route name/definition
validate({ body: orderSchema }), // validation middleware
createOrderController // controller
)
In this case, validate()
is a JSON Schema middleware library function, and that Schema is defined for an order. If the request that the REST API receives is invalid - for example, maybe it's missing the total
field - then the request will stop and return, skipping the controller.
Summary
Next time you are setting up request validation, put it into a middleware function before your controllers/route handlers. This way the code will exit as early as possible and you won't spend valuable server resource time and compute power, and will return a response to the client as quickly as possible.
Found this post helpful? One of the most frustrating things with Node is how there aren't many "official" patterns - defined by the language itself or the popular frameworks - for ways to do things, like how to structure your REST API's. Figuring out where request validation code goes is one part of figuring out how to structure your app, but it's only one part of the puzzle. If you want the rest of the picture, sign up below to receive a template repo with the structure I use for all my Express REST API's and a post explaining in detail what logic goes where within that structure. You'll also receive all my future posts directly to your inbox!
Subscribe for the repo!
No spam ever. Unsubscribe any time.