JSON.stringify api response in express - javascript

I'm reading some codes and I saw this
router.post('/', (req, res) => {
const {author, message} = req.body;
if (author === undefined) {
res.status(400);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ message: 'Every message requires an author' }));
return
}
res.redirect('/');
});
I've no clue why it need to use JSON.stringify, can't I just do res.send({ message: 'Every message requires an author' }) ?
And the route has an unit test, it used JSON.parse
describe('when the author is blank', () => {
it('renders an error message', async () => {
const message = 'Server Testing';
const response = await request(app)
.post('/messages')
.send({message});
assert.equal(response.status, 400);
assert.equal(JSON.parse(response.text).message, 'Every message requires an author')
});
});
I don't see the point of using JSON.stringify and JSON.parse, please enlighten me.

You can remove but it may lead to some unexpected results at times even if you are passing exact json. I will share an example with you.
I was working on a project where in I need to send a hotel id in json format .I was sending the exact format but server was not accepting that and was throwing 500 error so it's always better to stay on a safer side and declare your data in a separate variable and pass in that data using json.stringify format in the get/post request.It comes good practices.
So it's always good to have those :-)

Server side use:
res.json({a: 123})
instead of
res.send(JSON.stringify({a: 123}))
http://expressjs.com/en/api.html#req.body
Then in the unit test:
const response = await request(app).post('/messages').send({message});
const data = await response.json();

Related

How to send data from NodeJS server side to the JS client side, only when data is ready?

On my website, when the user clicks on a button, some user's data will be stored in a database and after that I want the server to send notification data to the Javascript frontend file to change the UI.
Right now, the Js file (index.js) receives data right after the website loads (always false). I want it to be received only when the data is ready on the server.
I searched a lot but couldn't find an answer to my problem?
I appreciate any help :)
server.js
var requestValidation = false;
app.post("/", function(req, res){
var name = req.body.personName;
var email = req.body.personEmail;
var collabTopic = req.body.collabTopic;
const newUser = new User({ //mongoDB schema
name: name,
email: email,
collabTopic: collabTopic
});
newUser.save(function(err){ //adding data to mongoDB
if(!err){
requestValidation = true;
}
});
});
app.get("/succ", function(req, res){
res.json(requestValidation);
});
index.js
const url = "http://localhost:3000/succ";
const getData = async (url) => {
try {
const response = await fetch(url);
const json = await response.json();
console.log(json);
} catch (error) {
console.log(error);
}
};
getData(url);
I'm not sure this is completely the answer you're looking for, but it's definitely a tool/feature to consider as you rework your approach.
app.post("/", async (req, res) => {
let result = await INSERT MONGODB UPDATE OR INSERT FUNCTION;
res.render("YOUR TEMPLATE", result);
});
You probably can't plug and play this, but when you finish a MongoDB operation, it returns a json object with some details on whether or not there was success. For example, a MongoDB insert operation returns something like this (stored in the variable result that I created)
{ "acknowledged" : true, "insertedId" : ObjectId("5fd989674e6b9ceb8665c57d") }
and then you can pass this value on as you wish.
Edit: This is what tkausl referred to in a comment.
Here is an example if you want to pass the content of a txt file to the client with express and jquery:
in express:
app.get('/get', (req, res) => {
fs.readFile('test.txt', (err, data) => {
if (err) throw err;
return res.json(JSON.parse(data));
})
})
jquery in client side:
$.getJSON( "http://localhost:3000/get", function( data ) {
geojsondata1 = JSON.stringify(data)
}
now you can do anything you want with the variable data

Why downloading a file from node.js server multiple times results in empty files

I am glad to get some help.
Here is my problem:
I have built a web server with node.js that should send a csv file to the client when requested through a certain route. The csv file is created from json using the fast-csv package. The json data comes from a mongoDB and is processed with mongoose.
When I request this route once, it works fine. However, when it is requested a second time, an empty file is sent to the client. By the way, the headers reach the client correctly.
I have to restart the server to download my file again.
What did I try:
Basically, I have now lost track of everything I have tried. This behavior occurs both when using postman and when querying via the browser.
I've tried implementing promises in my handler function.
I've tried to unsubscribe
res somehow (but yes, that was a stupid approach).
I`ve tried to write the file into the fs and to send it on a second request. ...
Maybe one of you can tell what's going wrong here at first glance:
const { format } = require("#fast-csv/format");
const csvStream = format({ delimiter: ";", headers: true });
const router = express.Router();
router.route("/:collection/csv").get(requireModel, createCsv);
const csvFromDatabase = (data, res) => {
csvStream.pipe(res);
const processData = (data) => {
data.forEach((row) => {
const { _id, __v, ...newRow } = row._doc;
csvStream.write({ ...newRow });
});
csvStream.end();
};
processData(data);
};
const createCsv = async (req, res) => {
const { model } = req;
const items = await model.find({});
res.setHeader("Content-disposition", "attachment; filename=file.csv");
res.setHeader("Content-type", "text/html; charset=UTF-8");
csvFromDatabase(items, res);
};
Thank you very much for your help. I hope I didn't bore you with too stupid questions.
You need to recreate csvStream for each new request:
const csvFromDatabase = (data, res) => {
const csvStream = format({ delimiter: ";", headers: true });
csvStream.pipe(res);
…
};

I have a problem validating on update (express)

I'm trying to create a validator that will display an error message when a user tries to update a column that doesn't exist in the database schema. I'm using PostgreSQL. When I send a request with the correct allowed updates it returns an error: 'Invalid updates' What am I missing?
const updateQuestion = async (req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ['title', 'text, questionCateg']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send({
error: 'Invalid updates'
})
}
try {
const {
id
} = req.params;
const {
title,
text,
questionCateg
} = req.body
const updateQuestion = await pool.query("UPDATE Questions SET title = $1, text = $2, questionCateg = $3 WHERE id =$4",
[title, text, questionCateg, id]);
console.log(updateQuestion)
res.json('Question updated')
} catch (e) {
res.status(400).send()
}
}
Route:
router.patch('/questions/:id', updateQuestion)
Thanks in advance!
What do you see when you console.log(req.body) ? you should concentrate on that updates array.
You can use body-parser in your app.js or express.json() middleware
This way you can succesfully receive your items that you are sending to your backend.
You can send the updates in post request body with the key updates. Then you can parse it like req.body.updates (updates is an array)
You can use body parser like this
app.use(bodyParser.urlencoded({
extended: true
}));
or app.use(express.json())
you can see further information in this post express.json() and express.urlencoded()

How do I do a GET for Firebase.functions().httpsCallable?

How do I do a GET for Firebase.functions().httpsCallable?
I keep receiving a POST error 404 but this is a GET request to my server. Should I pass in nothing or there is something to change this httpsCallable to get function?
Client
let updateWorkshop = Firebase.functions().httpsCallable('api/update/workshop');
updateWorkshop({/* nothing */})
.then(res => {
console.log(res);
}, err => {
console.log(err);
})
Server
app.get('/v3/update/workshop', asyncMiddleware( async (req, res, next) => {
let results = await UPDATE_WORKSHOP_DATE.Run()
res.status(200).json({results: results})
}))
exports.api = FUNCTIONS.https.onRequest(app);
If you are just trying to ping your callable function endpoint, a GET won't work. As you can see from the protocol specification for callable functions, it uses a POST. If you use a GET, it's an error because you're not following the protocol.

Using chai to mock http requests

I'm testing a nodejs app written using express. For the unit testing I'm using chai and sinon. I have the following route in my API that I would like to test.
In my test, I'm simulating the get request with the following code:
chai.request(app)
.get('/downloads')
.send({ wmauth: {
_identity: {
cn: "username",
}
} })
.end((err, res) => {
res.status.should.be.equal(200);
res.body.should.be.a('object');
res.body.should.have.property('Items', []);
AWS.restore('DynamoDB.DocumentClient');
done();
However, I'm always getting the error "Cannot read property '_identity' of undefined". Because the object "wmauth" is not sent in the request, so it is undefined. I have tried to use the send method to try to include it in the request, but no luck. I guess I need to mock it somehow and send it into the request but have no idea how to do it. Could someone help me with this?
Below the method to test:
app.get('/downloads', async (req, res) => {
const created_by_cn = req.wmauth['_identity'].cn;
if(!created_by_cn) {
return res.status(400).json({
error: 'Mandatory parameters: created_by_cn',
});
}
try {
const data = await downloadService.getDownloads(created_by_cn);
return res.status(200).json(data);
}
catch(error){
res.status(500).json({error: error.message});
}
});
THanks
I guess you forgot to use req.body as in:
const created_by_cn = req.body.wmauth['_identity'].cn;
Hope can solve your issue
Since chai-http use superagent, so according to its doc, you need to use query() in order to pass query parameter in get request:
chai.request(app)
.get('/downloads')
.query({ wmauth: {_identity: {cn: "username"}}})
.end((err, res) => { ... });
Then in the express route you can find the parameters in req.query:
app.get('/downloads', function (req, res) {
const created_by_cn = req.query.wmauth._identity.cn;
...
})

Categories