Reputation: 117
I'm working on learning Express JS and practicing security. I have moved some coupon code logic to the server, to make it more secure. That means that I send a coupon code to the server, it checks whether it is a valid code, and then returns a JSON object with a message and a win indicator (1 for the win, 0 for loss).
My issue is that I cannot figure out how to get both the message and the win indicator on the client from the response. It's always undefined
This is the client:
window.addEventListener("load", () => {
const nameInput = document.getElementById("name");
const couponCodeInput = document.getElementById("coupon-code");
const button = document.getElementById("button");
const nowinElem = document.getElementById("no-win");
const winElem = document.getElementById("you-won");
button.addEventListener("click", async e => {
e.preventDefault();
winElem.style.display = "none"; //new click of button:
nowinElem.style.display = "none"; // hide previous messages
let resp = await fetch('winner', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: nameInput.value, code: couponCodeInput.value })
});
if (resp.status !== 200) console.log('Winner report failed');
var res = resp.body;
if(res.win == "1"){
winElem.style.display = "block";
winElem.innerText = res.msg;
} else {
nowinElem.style.display = "block";
nowinElem.innerText = res.msg;
}
})
})
And this is the server:
const express = require('express')
const fs = require('fs')
const app = express()
const html = fs.readFileSync('coupon-client.html');
const js = fs.readFileSync('coupon-client.js');
const winnerCodes = ["123", "secret", "abc321"];
app.get('/', (req, res) => {
res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"});
res.end(html);
})
app.get('/coupon-client.js', (req, res) => {
res.writeHead(200, {"Content-Type": "application/javascript"});
res.end(js);
})
app.post('/winner', express.json(), (req, res) => {//use built-in JSON middle-ware
let jsonObj = req.body //JSON already parsed: { "name": "my name" }
if(winnerCodes.includes(jsonObj.code)){
console.log(`Congratulations to ${jsonObj.name}!`);
console.log("We'll send you a diploma.");
res.json({msg: 'Congratulations - and thanks!', win: '1'});
} else {
console.log(`Condolences to ${jsonObj.name}!`);
console.log("We'll send you nothing.");
res.json({msg: 'Sorry, you did not win - but thanks for playing!', win: '0'});
}
})
app.listen(8080, () => console.log('Listening...'))
As I mentioned above, I cannot get the JSON data object to give me the win and message variables. I have tried to do "JSON.parse(resp.body)" but then it gives me an error saying "unexpected character at....", which I read means that the body is already parsed, so I'm just taking the body now.
Can anyone give me a hint or help me out?
Upvotes: 1
Views: 675
Reputation: 20944
Reading a Response
object works differently from how you currently are using it.
Use the json()
method on the response object. It will return a promise which parses the response from JSON into usable data.
About the Response
object and its usage.
Currently you're accessing the body
property on the Response
object, which it inherited from the Body
mixin.
The body read-only property of the Body mixin is a simple getter used to expose a ReadableStream of the body contents. MDN
So you're accessing a ReadableStream
object and try to read the win
property from it, which doesn't exist on the stream.
To help with this the Body
mixin has methods to convert the stream into usable data. Examples are Body.json()
and Body.text()
. These methods read the stream and convert the body into an object, array, string or number when it has a JSON structure or into a single string, which is useful when you're sending HTML or just raw text.
Both methods return Promises in which you have to wait for the result to be ready for usage.
let resp = await fetch('winner', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: nameInput.value,
code: couponCodeInput.value
})
});
if (resp.status !== 200) console.log('Winner report failed');
// Decode body from JSON.
let { win, msg } = await resp.json();
if (win === "1") {
winElem.style.display = "block";
winElem.innerText = msg;
} else {
nowinElem.style.display = "block";
nowinElem.value = msg;
}
Upvotes: 2