I am using sails js for my web application. I have to change the default behaviour of beforeCreate. First look at the code:
beforeCreate: function(values, next) {
//ParamsCheck is my service and 'check' is method which will validate the
//parameters and if any invalid parameter then error will be thrown, otherwise
//no error will be thrown
ParamsCheck.check(values)
.then(() => {
// All Params are valid and no error
next();
})
.catch((err) => {
//Some errors in params, and error is thrown
next(err);
});
}
So, the problem is if there is any error, then next method is automatically redirecting to serverError with error code 500, while I want to redirect it with my custom response(eg : badRequest , err code 400). How to achieve this?
You are performing some kind of validation in beforeCreate. However this is not the correct place for validation.
A better approach is to use custom validation rules as described here http://sailsjs.org/documentation/concepts/models-and-orm/validations#?custom-validation-rules or create a policy to handle the validation.
I like to use policies:
module.exports = function(req, res, next) {
var values = req.body;
ParamsCheck.check(values).then(() => {
return next();
}).catch((err) => {
return res.send(422); // entity could not be processed
});
};
Related
I am reading a code that has two files like below:
first file that uses the currentuser middleware:
const router = express.Router();
router.get("/api/users/currentuser", currentUser, (req, res) => {
res.send({ currentUser: req.currentUser || null });
});
export { router as currentUserRouter };
Second file that defines the middleware:
interface UserPayload {
id: string;
email: string;
}
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
export const currentUser = (
req: Request,
res: Response,
next: NextFunction
) => {
if (!req.session?.jwt) {
return next();
}
try {
const payload = jwt.verify(
req.session.jwt,
process.env.JWT_KEY!
) as UserPayload;
req.currentUser = payload;
} catch (err) {}
next();
};
I understand that if there is a verified jwt token, the middleware will take the the payload out of it and add it to the req object. But what if it fails and it can't add the payload/current user to the req? What would happen for the following request and what will the res object look like?
router.get("/api/users/currentuser", currentUser, (req, res) => {
res.send({ currentUser: req.currentUser || null });
});
Could you edit this get request to show how can I catch the probable error if I am not the writer of the middleware?
If you had a catchall exception handler, and your middleware threw an exception, you would determine the response.
If your middleware threw an exception and you did not catch it, the system might just exit the process.
If your middleware did not throw an exception, and did not call next(), and did not respond, the request would hang.
If your middleware returned a response, and did not call next(), your send function would never get invoked.
The bottom line is that you need to dump the response on your server and see exactly how your middleware handles this.
In most of my auth middleware, I choose to not call next(), and return a 403 error. But there are some benefits by throwing an exception, then returning a 403 from a catchall handler.
You need to respond with an error HTTP status code, and an error message in the body. The exact status and message depends on the type of the exception and its parameters, so you need to catch it and check it.
The current express middleware does not handle errors, it just does not set the req.currentUser = payload;, so you won't know about the user. I don't think this is a proper solution for an authentication error.
In the documentation you can see how error are handled:
https://expressjs.com/en/guide/using-middleware.html
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
So I would rewrite the code and if the JWT verification fails, then I return for example 401 unauthorized. https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401
I guess you are using this JWT library: https://github.com/auth0/node-jsonwebtoken According to the docs and the code there are 3 types of errors: TokenExpiredError, JsonWebTokenError, NotBeforeError for verify. Here you can check when they are thrown: https://github.com/auth0/node-jsonwebtoken/blob/master/verify.js , here are their definitions: https://github.com/auth0/node-jsonwebtoken/tree/master/lib
So in the catch block you just check the type of the error with instanceof e.g. if (err instanceof jwt.JsonWebTokenError) ... and send the message accordingly with the res.status(401) and put the next() to the end of the try block, because it should be called only if the verification does not fail.
app.get('/api/v3/app/events', async function (req, res){
try {
let unique_id=req.query.id
console.log(unique_id)
database.collection('event').findOne(ObjectId(unique_id),function(err,data){
if(err){
res.json({error:"no data found with specified id"})
}
console.log(data)
res.json(data)}
)
} catch (error) {
console.log("internal error")
res.json({error:error})
}
})
app.get('/api/v3/app/events', function(req,res) {
try {
let limit=parseInt(req.query.limit)
let page =parseInt(req.query.page)
console.log(database.collection('event').find().sort({$natural: -1}).limit(limit).skip(page-1).toArray((err, result) => {
console.log(result);
})
)
} catch (error) {
console.log(error)
return res.json({error:"internal error "})
}
})
I have to perform these functionalities with same base url i.e '/api/v3/app/events'.
Please help . I am successful as I change the names of endpoints, but keeping them same , I gets null and undefined on the console
I'm not sure why do you need both to use same URL, but you have two choices either use a single endpoint with both of the logics. The other option would be to use the next middleware based on the id query param like this:
app.get('/api/v3/app/events', async function (req, res, next){
if (!req.query.id) {
next();
return;
}
// Rest of your endpoint logic
}
Each endpoint in Express is considered as middleware. This means that response won't be sent back, but calling the next() middleware instead and allow other middlewares to be executed. You can use same if or modify it based on your login.
I am building a Node JS application. I am using Sentry, https://docs.sentry.io/platforms/node/ in my application to monitor and report errors. But I am having a problem with global reporting for try catch block.
For example, I have a code block as follow.
const getUser = async (id) => {
try {
//do the database operation and return user
} catch (e) {
return {
data: null,
message: e.message
}
}
}
As you can see in the code, I am catching the error in the Try catch block. If I want to report the error to Sentry, I have to put in the following line in the catch block.
Sentry.captureException(e);
Basically, I am explicitly reporting the error. Is there a way to globally and automatically catch the error within the catch block and report it to the sentry. For, example, something like in PHP or Laravel. We will just have to initialize and configure the Sentry in one centralized place of the application and app will report any errors to the Sentry.
Sentry starts monitoring the whole application just by adding, the init function, somewhere in a global scope.
For example :
Sentry.init({
debug: appConfig.env === 'staging',
dsn: appConfig.sentryDSN,
environment: appConfig.env,
integrations: [new Integrations.BrowserTracing()],
release: [pjson.name, pjson.version].join('#'),
tracesSampleRate: 1.0,
ignoreErrors: [],
normalizeDepth: 10, // Or however deep you want your state context to be.
// (breadcrumb: Breadcrumb, hint?: BreadcrumbHint | undefined) => Breadcrumb | null
beforeBreadcrumb(breadcrumb: Sentry.Breadcrumb, hint: Sentry.BreadcrumbHint | undefined) {
return breadcrumb.category === 'xhr' ? breadcrumb : null;
},
});
You can stay just to that 'conf/init' if you like, this captures some errors, which are: `every error that inherits from the 'Error' object, like: TypeError, RangeError, ReferenceError, SyntaxError, etc , for more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
But its better to handle the errors explicitly, and have the power to control what you want to send to Sentry(add/filter breadcrumbs, add tags, extra data etc).
In my reactjs app i have a middleware that all the errors are sent there, and inside there there is a logic..
Similarly i d suggest an error middleware where all the errors are send there, and at that middleware you exlicitly handle & send them to Sentry.
I assume the the tech stack node + express, so i d suggest, in the routes catch, to call next(error):
router.get('/path', function(req, res, next){
const getUser = async (id) => {
try {
//do the database operation and return user
} catch (error) {
//return {
// data: null,
// message: e.message
// }
next(error)
}
}
})
**OR based on Express 5, route handlers that return Promise will call next(value) automatically when they reject or throw an error **:
app.get('/path', async function (req, res, next) {
var user = await getUser(id)
res.send(user)
})
And into the app.js, you put the error handler middleware where it handles the errors..:
app.use(function(err, req, res, next){
// filter the error
// send it to Sentry
if(condition){
// add custom breadcrumb
Sentry.addBreadcrumb({
type: Sentry.Severity.Error,
category,
message,
level: Sentry.Severity.Error,
});
Sentry.configureScope((scope: any) => {
scope.setTag('section', section);// add tag
Sentry.captureException(error, scope); // capture the error
});
}
})
I have been looking through some code online for building a React to-do app that uses an Express backend. The link to the website is here, and I came across this part of the code:
app.get("/todos", async (req, res, next) => {
try {
const todos = await db.Todo.find({});
return success(res, todos);
} catch (err) {
next({ status: 400, message: "failed to get todos" });
}
});
I know that the next function is a function that passes the operation of the current middleware function that it is in to the next middleware function of the same route. However, sources online just use the simple "next()" function, but this code has a value, an object, that is passed into the next function.
What does this mean?
this code has a value, an object, that is passed into the next function. What does this mean?
Ans: This means that you are passing an object as a parameter to the next middleware function.
app.use((err, req, res, next) => {
return res.status(err.status || 400).json({
status: err.status || 400,
message: err.message || "there was an error processing request"
});
});
Here err parameter is the object that you have passed.
Hope this helps
It seems to be a naming convention in Node.js, used to control the next matching route.
This stuff is frequently found, also very handy, and mostly used in access checks or wildcard routes. (/user/:id)
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in. If not, redirect to login.
if (!store.getters.isLoggedIn) {
next({
path: `/${ViewName.UserLogin}`,
query: { redirect: to.fullPath }
});
} else {
next();
}
}
From the express documentation:
Starting with Express 5, middleware functions that return a Promise will call next(value) when they reject or throw an error. next will be called with either the rejected value or the thrown Error.
So it seems to me like the value inside the next() function is the return value that is sent to the next callback. Often you don't want to send a custom value and just go to the next middleware function, however in this case they apparently wanted to set the error message inside the next() function and thus override any default values.
Hope this helps
i tried to find a solution for this warning i get, but none of the suggested approaches worked for me. I don't want to disable this warning, because i believe this warning is there for a reason, but i can't figure out whats the real deal here.
I have the following route defined on my node.js server running express:
// GET all items
router.get('', helpers.loginRequired, function(req, res) {
debug("Get all items");
return knex.select('*').from('routes')
.then((routes) => {
res.send(routes);
return null;
})
.catch((err) => {
debug("error getting routes");
res.send({ error: "Fehler beim Laden" });
return null;
});
});
My Middleware loginRequired does not use any promise at all
function loginRequired(req, res, next) {
if (!req.user) {
req.flash('loginMessage', 'Du musst eingeloggt sein!');
req.session.redirectTo = req.path;
return res.redirect('/');
} else {
return next();
}
}
I use knex for accessing my database, which creates promises.
And everytime i hit the route, i get the following warning:
(node:10568) Warning: a promise was created in a handler but was not returned fr
om it, see *link*
at Function.Promise.attempt.Promise.try (C:\Users\qxr1088\Desktop\Privat\GPS
\bibis-tracker\node_modules\bluebird\js\release\method.js:29:9)
As you can see i tried to add the "return null;" statements as suggested by bluebird, but this does not fix the problem.