Internal Server Error on failed in router - javascript

In my router, before I goes to the page I launch an rest api request to get data from server in by beforeEnter clause like below:
beforeEnter: (to, form, next) => {
getData().then(
(response) => {
//some logic to get data
next(); //if no error redirect to page
},
(error) => {
next(false); //on error not redirect on page - on this moment i want to show info about internal server error
});
}
and right now i have an question, how to show an toast/notification with "Internal server error" info when I have an error in my beforeEnter?
thanks for any help

Hmmm, Ok, I do it
on error:
(error) => {
HelpersService.internalServerErrorToast();
next(false);
}
in service:
internalServerErrorToast() {
let bootStrapToaster = new BToast();
bootStrapToaster.$bvToast.toast("500", {
title: "Internal Server Error",
toaster: "b-toaster-bottom-right",
solid: true,
variant: "danger",
appendToast: false,
noCloseButton: true,
toastClass: "internalErrorToast",
});
}

Why you are not using catch. If you are using then, you can use catch.
beforeEnter: function(to, form, next) {
this.getData().then((response) => {
next();
}).catch(error => {
throw error
})
}
Try this. If not work, comment, We will do something else.

Related

The reason of ERR_HTTP_HEADERS_SENT error in Express.js middleware

I have created middleware to validate fields in body, here is how it looks like:
Front-end route:
router.post('/s-i', async (req, res) => {
try {
const { data } = await api.post('/sign-in', req.body)
res.cookie("_rt", data._rt, { httpOnly: true, secure: false })
delete data._rt
return res.json(data)
} catch (e) {
// Here is error
return res.status(e.response.status).json(e.response.data)
}
});
Route (back-end):
router.post('/sign-in', v(['email', 'password', 'twoFa', 'phone']), wrapAsync(userController.signIn));
Middleware:
exports.v = fields => {
return (req, res, next) => {
fields.forEach(field => {
if (req.body[field]) {
const result = require(`./validators/${field}`)(req.body[field])
if (!result)
return res.status(400).json({ message: 'bad-request', status: 400 })
}
})
next()
}
}
In the place where comment is placed I can see this error, actually, everything works find, and if there is wrong field in body front will receive 400 status code, but in back-end terminal I still have this error and can't get why.
The problem is I still keep getting this ERR_HTTP_HEADERS_SENT error. I know the reason of this problem - for example - if you are trying do res.send({}) twice, but I don't really see the reason of problem in this case.
The return res.status(400)... statement returns only from the inner function fields.forEach(field => {...}), but you must return from the middleware function, otherwise the next() will invoke subsequent middlewares after the .json output, leading to the observed error.
You can achieve this by replacing fields.forEach(field => {...}) with
for (var field of fields) {
if (req.body[field]) {
const result = require(`./validators/${field}`)(req.body[field])
if (!result)
return res.status(400).json({ message: 'bad-request', status: 400 })
}
}

Nuxt and Vue Apollo. How to handle errors inside Smart Query with redirection to 404/400/500 error page? Can we catch such errors?

With regular HTTP request, we may create redirection with asyncData({error}){...}
What should we use for redirecting to 400 page using Smart Query?
With Vue Apollo, I am trying to use
apollo: {
queryName: {
prefetch: true,
query: wrongQuery,
error(errorData) {
this.$nuxt.error({
statusCode: 500,
message: 'Error message',
});
},
},
};
In case if we reload the page, redirection doesn't work. We still got an error becouse server side rendering:
With global error handler like:
// /plugins/apollo-error-handler.js
export default ({ graphQLErrors, networkError, operation, forward }, nuxtContext) => {
console.log(networkError)
nuxtContext.error({
statusCode: 404,
message: 'Error message',
});
};
Only errors logging works. Redirection doesn't work at all.
Do we have any way to handle errors inside smart queries with redirection to 400 page for example?
Can we catch such errors in smart query? Like try...catch... in asyncData() to prevent app crash.
I found the solution here!
export default function ({ redirect }) {
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(({ message }) => {
if (`${message}` === 'Unauthenticated.') {
redirect('/login')
// Do Something
localStorage.setItem('logged', false)
}
})
}
if (networkError) {
console.log(`[Network error]: ${networkError}`)
}
})
return {
defaultHttpLink: false,
link: ApolloLink.from([link, createHttpLink({
credentials: 'include',
uri: 'http://localhost:8000/graphql',
fetch: (uri, options) => {
options.headers['X-XSRF-TOKEN'] = Cookies.get('XSRF-TOKEN')
return fetch(uri, options)
}
})]),
cache: new InMemoryCache()
}
}`
Hopefully this answer helpful for you!
Cheers!
The smart query like this is pretty limited and so, I prefer to handle it in my Vuex store. Not sure if it's the best practice but it works great for me right now.
async niceFancyVuexAction({ dispatch }, { fancyInput }) {
try {
const { errors, data } = await this.app.apolloProvider.defaultClient.mutate({
mutation: yourGraphqlMutationHere,
errorPolicy: 'all',
variables: {
input: fancyInput,
},
})
if (errors) {
return dispatch('handleErrors', 'we got some errors')
}
dispatch('anotherNiceFancyVuexAction', data.Address.createForCompany)
console.log('success !')
} catch (error) {
// here, you could catch the error and maybe make a redirect
dispatch('handleErrors', 'the call was not successfull')
}
},
Otherwise, yeah using the onError link is also a good idea if you feel configuring it: https://www.apollographql.com/docs/react/data/error-handling/

Express single response workaround

I am stuck in a bit of a dilemma here where once my user logs in I want to redirect them to the dashbord page but also send their json details to my client side javascript. I know that there can only be one res. send /end/json in a response and that I can send dynamic data using view engines.The reason why I want to send data separately is because I do not merely want to render it but rather use the data in my client side JS so that I can use it later for sockets in a chat application. I have tried a lot of things from using continuous local variables to try and create a middleware or an automatic redirect. The problem is no matter what the res.json() is hard to embed in a middleware as the very moment it is called there is no scope for declaring a next or redirect. Here is what my code looks like for the login route:
router.get(’/’, (req,res)=>{
console.log(req.user._id);
User.findOne({
"_id": req.user._id
}, function(err, foundUser) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundUser); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundUser
});
}
});
res.sendFile('chat.html', { root: path.join(__dirname, '../views/') });
});
you can make ajax request from your page to fetch the data you want and save it in your client side.
You need to make your chat.html page request the json data. This means you need two routes:
router.get(’/’, (req,res)=>{
es.sendFile('chat.html', { root: path.join(__dirname, '../views/') });
});
router.get(’/myself’, (req,res)=>{ // I normally call this route "myself"
// but you can call it anything you want
console.log(req.user._id);
User.findOne({
"_id": req.user._id
}, function(err, foundUser) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundUser); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundUser
});
}
});
});
Now you need your chat.html file to make a request for the new /myself data. There are various ways to do this but for modern browsers you can use fetch:
chat.html
<html>
<head>
... rest of your html head
<script>
fetch('/myself')
.then(res => res.json())
.then(res => {
if (res.ok === false) {
// Handle your error here, I'm just alerting it:
alert(res.error);
}
else {
let user = res.data;
// Now you can do anything with the user data
// in here. I'm just logging it:
console.log('user =', user);
}
});
</script>
</head>
<body>
... rest of your html code
</body>
</html>

Express.js - Cannot Set Headers with exported function

Learning how to do testing with Express with using Mocha, Chai, Chai-HTTP plugin, and MongoDB with Mongoose. I have a test to purposely detect if MongoDB will send back an error from trying to find a document using a faulty _id value (too short).
I noticed that part of my code is repeating around my other Express routes, and want to reuse it for other routes so I exported it from another module, but now I get this:
Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Not sure why I am getting this error. If I have the same code, as the exported function, inside the route code it works fine, but exported it just complains.
Here is the code:
test/route/example.test.js Snippit
it('Bad request with a too short ID string (12 characters minimum)', () => {
// /api/v1/example is the endpoint
// /blah is the param
chai.request(app).get('/api/v1/example/blah').end((err, res) => {
// Insert all the nice assert stuff. :)
});
});
route/example.js Snippit
// Packages
const router = require('express').Router();
// Models (Mongoose Schemas)
const Example = require('../models/example.model');
// Helpers
const { foundMongoError } = require('../helpers/routes');
// -----Snipped-----
router.route('/:exampleId').get((req, res) => {
// Retrieve the exampleId parameter.
const exampleId = req.params.exampleId;
Example.findById(exampleId, (mongoError, mongoResponse) => {
foundMongoError(mongoError, res); // Having an issue
// If I have the same code that makes up foundMongoError inside here, no issues,
// but it will no longer be DRY.
// Check if any responses from MongoDB
if(mongoResponse) {
res.status(200).json(mongoResponse);
} else {
return res.status(404).json({
errorCode: 404,
errorCodeMessage: 'Not Found',
errorMessage: `Unable to find example with id: ${exampleId}.`
});
}
});
});
helpers/routes.js
const foundMongoError = (mongoError, res) => {
if(mongoError) {
return res.status(400).json({
errorCode: 400,
errorCodeMessage: 'Bad Request',
errorMessage: mongoError.message
});
}
};
module.exports = {
foundMongoError
};
That just means you send and response res twice back. The first time you send it back at here:
if(mongoError) {
return res.status(400).json({
errorCode: 400,
errorCodeMessage: 'Bad Request',
errorMessage: mongoError.message
});
}
You sended an response back but the function still continue its work, that means the function moves on till here then:
if(mongoResponse) {
res.status(200).json(mongoResponse);
} else {
return res.status(404).json({
errorCode: 404,
errorCodeMessage: 'Not Found',
errorMessage: `Unable to find example with id: ${exampleId}.`
});
}
Here happens the second response, and here you get the error.
I would rewrite the code like this:
Instead of returning the response, you return an true that means there is an error, otherwise false :
const foundMongoError = (mongoError, res) => {
if(mongoError) {
res.status(400).json({
errorCode: 400,
errorCodeMessage: 'Bad Request',
errorMessage: mongoError.message
});
return true;
}
return false;
};
module.exports = {
foundMongoError
};
Then you can write it like this:
if(foundMongoError(mongoError, res)) return;
The return will stop the function to execute the rest of the code

Angular 4 & Passport API authentication

I'm building a web app with the MEAN Stack. What I am trying to achieve is that when the user logs in his user information get fetched by Angular from my REST API. I set up the API route http://localhost:3000/api/user/profile which should respond with json including the user object.
router.get('/user/profile', function(req, res, next){
//console.log(req);
if(req.user === undefined){
res.json({
success: false,
msg: 'Unautorized'
});
} else {
res.json({
success: true,
user: {
id: req.user.steam.id,
name: req.user.steam.name,
avatar: req.user.steam.avatar,
avatarmedium: req.user.steam.avatarmedium,
avatarfull: req.user.steam.avatarfull
}
});
}
});
When the user logs in Angular start a GET-Request:
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
console.log(profile);
},
err => {
console.log(err);
return false;
});
}
getProfile():
getProfile(){
return this.http.get('http://localhost:3000/api/user/profile')
.map(res => res.json());
}
When I load up my site, log in, and go to the profile page the returned object contains success: false and the message 'Unauthorized' instead of the user object. Why is this happening?
I completely redesigned my approach. I implemented json web token which now sends a token (containing all user data) to the user through a url parameter once he signs in.

Categories

Resources