ExpressJs returns empty res.json - json

When validating a mongoose schema in 'pre' of parallel middleware
schema.pre('save', true, function (next, done) {
if(...) {
next(new Error('Some error message'));
}
next();
});
I return an error and it is available in the callback function:
model.save({},{}, function(err) {
res.json(400, err);
console.log(err)// I see in the console: [Error: 'Some error message']
})
But when I do
res.json(400, err);
I get an empty response
{} No properties
What is the reason for this?

JSON can't stringify errors. You'll need to use something else to send the error.
Perhaps just res.send(err.message), or something similar.

Related

How can i stop further execution of express middleware

I want to get this functionality if(thereIsSomeError) //stop executing further. for example if there some error accurs in middleware or in the callback then i don't want to execute callback(in the app.route) and the middleware further
I tried this code. But i'm still getting req.err as true. how can i fix this issue
// My MiddleWare
export let Middleware=()=> {
return (req,res,next)=>{
next()
console.log(req.err) // Problem is here.. i'm still getting req.err(true)
if(!req.err){
db.query(`query`,(error, responseData)=>{
if(error) console.log(error)
db.query(`second query`,{...// send data to the
database})
})
}
}
}
//End point
app.post('/addStudent',Middleware, (req, res) => {
//setting error to true initially
req.err=true;
let data = req.body
db.query(`query `, data.username, (err, d) => {
if (err) return res.json(err)
else {
// since no Error accured so set the error to false
req.err=false;
let q = 'query';
let values = {//data here}
db.query(q, values, (err, data) => {
if (err) return res.status(200).json(err)
else return res.status(200).json({ data })
})
}
})
})
First, a middleware runs BEFORE a request, NOT AFTER. If you set req.err = true in your POST endpoint, IT WILL STAY TRUE, meaning your database call will certainly return an error.
Second, to successfully abort a middleware call, use return. Returning a function stops it immediately. You can choose either to return next(err) to forward the error to the handler, or to use return res.send('Error') to terminate the response in the middleware.

Unable to display the express res.send() custom error message on the vue side

I have a nuxt app with express and mySQL.
Problem : I am unable to display the express res.send() custom error message on the vue side
Let's pretend I want to display infos of one single user.
Here is my back-end code :
// Find a single User with a userId
exports.findOne = (req, res) => {
User.findById(req.params.userId, (err, data) => {
if (err) {
if (err.kind === 'not_found') {
res.status(404).send({
message: `Not found User with id ${req.params.userId}.`
})
} else {
res.status(500).send({
message: 'Error retrieving User with id ' + req.params.userId
})
}
} else { res.send(data) }
})
}
And here is the Vue part
<script>
import axios from 'axios'
import appNavbar from '~/components/appNavbar.vue'
export default {
components: {
appNavbar
},
data () {
return {
userId: '',
userData: '',
errorMsg: ''
}
},
methods: {
fetchUser (evt) {
evt.preventDefault()
return axios.get('/api/users/' + this.userId)
.then((res) => {
this.userData = res.data
})
.catch((err) => {
this.errorMsg = err.toJSON()
})
}
}
}
</script>
When I give the id of a non-existing user, I want to be able to get the custom error message written in the back, and display it in the front
BUT I only get this JSON
{ "message": "Request failed with status code 404", "name": "Error" }
Does anyone have a clue ?
Thanks !
This error maybe occours because you are not setting the host when you call teh API at line:
return axios.get('/api/users/' + this.userId)
404 error is because browser not found this endpoint.
In this case, I recommend you try to call this endpoint in another tool (like Postman) and certify if your API is responding correctly.
After that, fix your call to endpoint, maybe it will be somwthing like the code bellow and try again:
return axios.get(`${your host here}/api/users/ + ${this.userId}`)
EDIT : SOLUTION FOUND
Answer found here: https://github.com/axios/axios/issues/960#issuecomment-309287911
On the vue part, the catch should return err.response, and not just err.
So in order to display your custom error message, it should be like this:
.catch((err) => {
this.errorMsg = err.response

Error Setting Headers After They are Sent - Node.js

I'm building an api with nodejs to interact with both the client(android) and the admin(web).
When the api is started, it works fine for the admin and the views are rendered properly but when I connect the client to the api, I get an error/warning in server console like:
App at port 4003
db connection opened successfully
Categroies Count: 2
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
at ServerResponse.setHeader (_http_outgoing.js:501:3)
at ServerResponse.header
(E:\nodeCMSApp\node_modules\express\lib\response.js:767:10)
at ServerResponse.json
(E:\nodeCMSApp\node_modules\express\lib\response.js:264:10)
at Categories.find.select.exec.then.data
(E:\nodeCMSApp\routes\admin_categories.js:20:22)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
(node:13880) UnhandledPromiseRejectionWarning: Unhandled promise
rejection (rejection id: 1): Error: Can't set headers after they are
sent.
(node:13880) [DEP0018] DeprecationWarning: Unhandled promise rejections
are deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with
a non-zero exit code.
Here's my api code snippet:
router.get('/', (req, res) => {
Categories.find({})
.select('title slug image _id')
.exec()
.then(data => {
if (data) {
res.status(200)
.json({
success: true,
count: data.length,
categories: data
})
// I understand that the problem lies here
res.render('admin/all_categories', {
categories: data
});
} else {
res.render('all_categories', {
categories: null
});
}
})
.catch(error => {
console.error(error);
res.send('Error 404');
});
});
I understand that it's because I have already rendered a view with the response object and I'm calling it again to return some json for the client.
My question is how do I render the view and return json data for the client concurrently withoutany errors?
Thanks.
In your code, you are sending two responses to user if all goes well:
if (data) {
res.status(200).json({
success: true,
count: data.length,
categories: data
});
// I understand that the problem lies here
res.render('admin/all_categories', {
categories: data
});
}
In the moment you perform some call to res.json, res.send, res.redirect, res.render, etc, you are sending the proper headers to user (browser) so, in your case, after res.status(200).json you are trying to send res.render and is not possible because first res.json started sending the result to the user. I guess you want to render all_categories with "data" so you should render the template in backend (compile) before send it to the user.

JSON structure output

I'm working on a school assignment, Node.js, and have trouble with getting my output correct. It's the res.end part that isn't working, but res.end(stdout); works. Why?
case "/status":
/**
* Run child process "uname -a".
*/
cp.exec("uname -a", (error, stdout, stderr) => {
if (error || stderr) {
// Do something with the error(s)
console.log("Something went wrong...", error, stderr);
}
// status route
res.writeHead(200, { "Content-Type": "application/json" });
res.end({
"uname": stdout
});
});
break;
As specified in the Node.js docs, res.end can only take a string or a buffer - or nothing at all - as its first parameter. If you wish to send JSON using it, you'll have to set the content type (which you've done) and stringify the object:
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({
"uname": stdout
}));
This is effectively what Express.js does when you call res.send/res.json on an object.

ECONNREFUSED when making GET request in app, but API returns JSON successfully

I'm writing a node app with React, using node-postgres and superagent for backend calls.
Let's say I'm making a GET request and using the JSON it returns to fill a table of students. My API looks like this:
import pg from 'pg';
import Router from 'express';
let router = new Router();
let conString = "postgres://user:pass#localhost/db_name";
router.get('/getStudents', function(req, res) {
var results = [];
pg.connect(conString, function(err, client, done) {
if (err) {
done();
console.log(err);
return res.status(500).json({success: false, data: err});
}
var query = client.query('SELECT first_name, last_name, email FROM students');
query.on('row', function(row) {
results.push(row);
});
query.on('end', function() {
done();
return res.json(results);
});
});
});
On page load, this is called from the store to set a students array. It seems like something is going wrong here:
var request = require('super agent');
function getStudents() {
request
.get('/api/getStudents')
.set('Accept', 'application/json')
.end(function(err, res) {
if (err) {
console.log("There's been an error: getting students.");
console.log(err);
} else {
return res;
}
});
}
If I curl localhost:3000/api/getStudents, I get the JSON response I expect.
However, when I call this on page load, I get an ECONNREFUSED error:
Error: connect ECONNREFUSED 127.0.0.1:80]
code: 'ECONNREFUSED',
errno: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 80,
response: undefined
Not sure why I'm getting an error on the HTTP port. This is my first time using node-postgres, superagent, and React so any help is appreciated.
Edit: Forgot to mention that I'm able to make POST requests and insert items into the database without any errors. This error only occurs when I'm attempting a GET request.
Try this (inserting the full path url) in the get method:
request
.get('http://localhost:3000/api/getStudents')
.set('Accept', 'application/json')
.end(function(err, res) {
if (err) {
console.log("There's been an error: getting students.");
console.log(err);
} else {
return res;
}
});
Check out the documentation for CORS for an example of using absolute urls:
https://visionmedia.github.io/superagent/#cors
The error will also occur if you don't have the protocol in your request URL.
Instead
request.get('www.myexample.com/api/getStudents')
do
request.get('https://www.myexample.com/api/getStudents')
^^^^^^^^