In my node application, I have the following express route.
router.post('/register', asyncMiddleware(async (req, res) => {
const { error } = validateUser(req.body);
if (error)
return res.status(400).send(error.details[0].message);
const { token, user } = await userService.createNewUser(req.body);
res.header('x-authorization-token', token).send(_.pick(user, ['_id', 'name', 'email']));
}));
Is it a good practice to handle validation results like this? Or should I put this in to a middlerware and use it? If so, how can I put this in to a middlerware and use it?
Is it a good practice to handle validation results like this?
The answer is that It Depends.
If it is a small project or there are only a few APIs or you need validation for only this route then probably you can get around with validation like this.
But, in bigger projects, you should definitely have a separate validation middleware.
I personally like to use express-validation along with Joi for validation.
Joi is great for creating flexible and powerful schemas to validate the incoming request. and express-validation takes care of the appropriate status and body.
If you want to see an example of this, checkout my express-api-structure.
Related
Am using express js on node for my api service ! In which am using sequelize for query handling purposes !
So in some usecase like creating record, or updating record its simply returning "1" or sometimes nothing !
In this case , am just using
res.sendStatus(200);
or sometimes
res.send("success");
Is there any better way or this is the correct way to handle ? Or should in need .end() in order to end the process ??
which is a good way to handle these kind of useless responses which we dont need to send back ?
This is where Status 204 comes in to play: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success
It states: everything is OK (like in 200), but there is simple no need to send a body.
Using express, it's just as simple as: res.sendStatus(204)
Usually a json is send back to the client with different information in it that lets the client-side know that the operation that they request through the api is successfull or failed. for e.g. here, you can define a standard json response like this
//in case of success of the request
{
requestStatus: 1,
...other data if you want to like new Id of the created data/updated data or info about it if you want or depending upon use case
}
or
// in case of failure of the request
{
requestStatus: 0,
...other data if you want to like reason for failure, error message or depending upon your use case
}
Just add this line of code, should be fine:
//For all bad endpoints
app.use('*', (req, res) => {
res.status(404).json({ msg: 'Not a good endpoint, why are you here? Go play FIFA.'})
})
If you want you can generate an error HTML file, but since it's back-end, JSON format is strongly suggested. You can also add success: false for more clarity.
I recently used nestjs, But I realized its overcomplicated, I mean look the following code:
#post('/products')
getAllProducts(#Body('title') title, #Body('price') price, #Body('description') description) { }
It makes function parameters much dirty, Also there could be more decorators above function like #Header, #Params, etc.. Which reduces readability in my opinion.
Same code in nodejs
const { title: title, price: price, description: description } = req.body
nodejs is much more readable...
Then I researched why developers use nestjs, Reason was Modularity. Why we don't implement this on our own...
See below:
See my directory sutructure
In app.js I just kicked the app:
const express = require('express');
const app = express();
// express config
require('./startup/config')(app);
// handling routes
require('./startup/routes')(app);
// db setup
require('./startup/db')(app);
In startup folder I did the basic work like mongoose configuration and connection to db etc..
However, In startup/routes, I just kicked the module as follow:
const shopModule = require('../shop/shop.module');
module.exports = app => {
app.use('/', shopModule);
};
In shop module, I just kicked the routes as follow:
const router = require('express').Router();
const productsRouter = require('./products/index');
const cartRouter = require('./cart/index');
// Products
router.use('/products', productsRouter)
// Cart
router.use('/cart', cartRouter)
module.exports = router;
Now in cart/index.js, I handled the routes related to cart and same for products as follow (I will just show cart):
const router = require('express').Router();
const { getCart } = require('./cart.controller');
router.get('/', getCart);
module.exports = router;
In controller, basically we will do validation stuff etc or extracting data.. Then controller will kick service for database work..
const { userCart } = require('./cart.service');
exports.getCart = (req, res, next) => {
const cart = userCart();
return res.status(200).json(cart);
};
And finally in cart service:
exports.userCart = _ => {
// ... go to database and fetch cart
return [{ prodId: 123, quantity: 2 }];
};
And cart.model.js is responsible for DB schema,
I know the question was too long, but I wanted to explain my question.
I am not saying nestjs should not be used, I am just saying, what about the following structure as it follows the same pattern as angular or nestjs, Right?
With your first point about making the code more readable, why not do something like
#Post('/products')
getAllProducts(#Body() body: any) {}
instead of calling for each part of the body individually, then you can deconstruct the body as you showed with
const {title: title, price: price, description: description} = body;
No need to specify each part of the body that you need as a new parameter, just grab the object itself. The same also goes for #Header(), #Param(), and #Query().
As for how you are setting up your express app, you are completely correct that you can do that; however, if you are working on an open source project, or collaborating with other developers there is nothing that says they have to follow the same format and it could eventually lead to a messy code base. Nest enforces these patterns, similar to how Angular does. Sure, it is still possible to write terrible code, but with an opinionated architecture it does make it more difficult.
NestJS also treats Typescript as a first class citizen, which in my opinion helps get rid of a lot of development problems as well. Plus you get some really cool packages to play with like class-validator and class-transformer to help with validation and transformation of your requests via pipes. You can write an Express server in Typescript, but it isn't necessary, and you can write a NestJS server in JavaScript, but I think you lose a lot of good functionality if you do.
The last point that I don't think has been touched too much it that Nest handles a lot of black boxing for your code through it's modules. If you define a service for a module, it is only available for that module. If you need it in another module you have options, but it helps cut down on the cross-contamination of code and keeps a separations of concerns ideology in mind.
In my opinion, the fact the NestJS gives us specified files for things like authentication (guards), validation and transformation (pipes and interceptors), and error handling (exception filters) makes it easier for anyone to pick up a NestJS server and have a quick understanding of how the request will flow through the server, even if by just looking at the file structure. Personally I know if I see an AuthModule or a guards folder I'm going to be dealing with authentication to some extent.
To answer your final question: there is nothing wrong with how you are showing the express example, especially as you are using Inversion of Control by passing the app into the router to make it work that way, you can absolutely write an Express server that way. Nest just makes you do it that way. (I mean, you could write an entire server using just AppController, AppService and AppModule, but that's really an anti-pattern)
In the end, definitely use what you're comfortable with, but there is a reason Nest has become so popular recently.
it's dirty because you write it in the wrong way
why not use it like this
#Get('/')
getAllProducts(#Body() product: Product) {}
and then destructure it
const {title, price, description} = product
I'm using koa2 and koa-router together with sequelize on top. I want to be able to control user access based on their roles in the database, and it's been working somewhat so far. I made my own RBAC implementation, but I'm having some trouble.
I need to quit execution BEFORE any endpoint is hit if the user doesn't have access, considering endpoints can do any action (like inserting a new item etc.). This makes perfect sense, I realize I could potentially use transactions with Sequelize, but I find that would add more overhead and deadline is closing in.
My implementation so far looks somewhat like the following:
// initialize.js
initalizeRoutes()
initializeServerMiddleware()
Server middleware is registered after routes.
// function initializeRoutes
app.router = require('koa-router')
app.router.use('*', access_control(app))
require('./routes_init')
routes_init just runs a function which recursively parses a folder and imports all middleware definitions.
// function initializeServerMiddleware
// blah blah bunch of middleware
app.server.use(app.router.routes()).use(app.router.allowedMethods())
This is just regular koa-router.
However, the issue arises in access_control.
I have one file (access_control_definitions.js) where I specify named routes, their respective sequelize model name, and what rules exists for the route. (e.g. what role, if the owner is able to access their own resource...) I calculate whether the requester owns a resource by a route param (e.g. resource ID is ctx.params.id). However, in this implementation, params don't seem to be parsed. I don't think it's right that I have to manually parse the params before koa-router does it. Is anyone able to identify a better way based on this that would solve ctx.params not being filled with the actual named parameter?
edit: I also created a GitHub issue for this, considering it seems to me like there's some funny business going on.
So if you look at router.js
layerChain = matchedLayers.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
ctx.routerName = layer.name;
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
What it does is that for every route function that you have, it add its own capturing layer to generate the params
Now this actually does make sense because you can have two middleware for same url with different parameters
router.use('/abc/:did', (ctx, next) => {
// ctx.router available
console.log('my request came here too', ctx.params.did)
if (next)
next();
});
router.get('/abc/:id', (ctx, next) => {
console.log('my request came here', ctx.params.id)
});
Now for the first handler a parameter id makes no sense and for the second one parameter did doesn't make any sense. Which means these parameters are specific to a handler and only make sense inside the handler. That is why it makes sense to not have the params that you expect to be there. I don't think it is a bug
And since you already found the workaround
const fromRouteId = pathToRegexp(ctx._matchedRoute).exec(ctx.captures[0])
You should use the same. Or a better one might be
var lastMatch = ctx.matched[ctx.matched.length-1];
params = lastMatch.params(ctx.originalUrl, lastMatch.captures(ctx.originalUrl), {})
I am developing a MEAN stack application but i stuck at validation(user-inputs). I know the client-side validations are done in Angular-JS but i am confused where to validate on server side. Either to use mongooose for validations or don't do any validation on mongooose(just store) do validations only in server(Node/express using some modules) or validate on both server-level and database-level....????
What should i do pls help me choose which practice is best.....????
Thanks.
As a MEAN stack developer there are various ways to validate the form...
1.) AngularJs form validations
2.) Mongoose Validation
3.) Backend Validation ( Express validator ot nodeValidator )
==> Validation in mongoose
Ex.
var userSchema = new Schema({
phone: {
type: String,
required: [true, 'User phone number required']
},
name: String,
subDoc: [
{
newName:String,
data:String
}
]
});
Above code shows simple integration of mongoose validator.
Validation in mongoose schema can create problems when writing the document
and worse situation can be generated when there are nested field and i am sure there will be. There are chances of modification of schema in such situation you to manage the validation, so much trouble i have faced..
So its a better IDEA to go with node validator or express validator which are super simple to use and provide lots of different type of validation options..
TRY
node-validator,
Express validator
js.com/package/node-validator
I personally suggest Express validator. which is simple and provide most of thing you need.
Banking just on mongoose validation is not enough. Your routes must be secured to not let invalid data pass through to mongoose validation.
The best place for this validation is middleware.
router.get('/', validateParameters, controller.index);
The function takes req, res and next. Call next if req parameters are valid, else respond with 400 status code. This way, only valid call reaches the end point.
function validateParameters(req, res, next){
// if req.params/req.body/req.query is valid
// return next();
// else return res.status(400).end;
}
As to actually how to validate, you can check express-validator package, which gives you lots of options to validate req body, query and params. One good option is creating a schema for each route and just passing that schema to validateParameters function and validating it with one of req.check(schema) (to check all), req.checkQuery(schema), req.checkBody(schema) orreq.checkParams(schema), depending on where your parameters are.
You may also want to take a look at mongoose-validatorjs.
I am building a nodejs + express RESTful server, and am trying to leverage middleware to ease authorization of specific actions.
What I am trying to achieve is to pass parameters to my authorization middleware functions. I was wondering if it is at all possible to do this in the routes or if I have to extract the parameters in the middleware function. I was hoping to avoid that behavior as I have been *hum* not entirely consistent in my URL parameter names.
What I would like to do is something like this:
router.get(
'/:productId',
auth.can_get_this_product(productId), // Pass the productId here
controller.perform_action_that_requires_authorization
);
But this is not possible. Because I have other routes where the names of parameters might not be the same (ie: router.get(/:p_id, auth.can_get_thi...). I realize I should probably just go back and make sure that my parameter names are consistent everywhere and retrieve the parameters in the middleware using req.param('productId')but I am curious if it would be at all possible.
Well, I suppose you can pass the params hash key and then use that.
router.get(
'/:productId',
auth.can_get_this_product('productId'), // Pass the productId *KEY* here
controller.perform_action_that_requires_authorization
);
//....
function can_get_this_product(productIdKey) {
var productId = req.params[productIdKey];
//....
}
But of course, we both know you should just bite the bullet and refactor those names.