why the REST API as a body gets undefined? - javascript

I writirng server in Express to posibility GET and POST. In Insomnia I get and post valid data.
This is code my REST.
const express = require('express');
const app = express();
const port = 3000;
var cors = require('cors');
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({extended: true}));
let myValue = 1;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
//GET
app.get('/get', (req, res) => {
return res.json({"wartosc": myValue})
});
//POST
app.post('/post', function (req, res) {
myValue = req.body.value;
console.log(req.body)
return res.json({"wartosc": myValue});
});
Then I creaeted page with two input will be used to call the GET and POST methods of our REST server.
async function getMethod() {
let inputValue = document.getElementById("inputValue").value;
const responseGet = await fetch('http://localhost:3000/get');
const myJsonGet = await responseGet.json();
//console.log(JSON.stringify(myJsonGet));
document.getElementById("inputValue").value = myJsonGet.wartosc;
}
async function postMethod(){
let inputValue = document.getElementById("inputValue").value;
let responsePost = await fetch('http://localhost:3000/post', {
method: 'POST',
body: {'value' : JSON.stringify(inputValue)}
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<input type="text" id="inputValue">
<button onclick="getMethod()"> GET</button>
<button onclick="postMethod()">POST</button>
<script src="script.js"></script>
</body>
</html>
When I do get , I get the correct value, but when I change the value and send a post, the server prints undefined.
I don't know why, will you try to help me?

In your script.js postMethod() you should stringify the entire body:
body: JSON.stringify({'value' : inputValue})
Ideally you use querystring.stringify instead but this should also work fine.
Alternatively, you can just leave out the entire script.js with the async stuff.
Instead try with using a form and name="value". You can change the form action and method per button.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="GET" action="http://localhost:3000/get">
<input type="text" id="value" name="value">
<button type="submit">GET</button>
<button type="submit" formmethod="post" formaction="http://localhost:3000/post">POST</button>
</form>
</body>
</html>

I did some changes to make it work on CodeSandbox (example). Everything works.
const express = require("express");
const app = express();
const port = 3000;
var cors = require("cors");
const rand = () =>
Math.random()
.toString(36)
.substr(2);
app.use(express.static("public"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
//GET
app.get("/get", (req, res) => {
return res.json({ getval: rand() });
});
//POST
app.post("/post", function(req, res) {
return res.json({ postval: `${rand()}:${req.body.value}` });
});
I put HTML and JavaScript files in the public directory.
async function getMethod() {
const responseGet = await fetch("/get");
const myJsonGet = await responseGet.json();
document.getElementById("inputValue").value = myJsonGet.getval;
}
async function postMethod() {
let inputValue = document.getElementById("inputValue").value;
let options = {
method: "POST",
body: JSON.stringify({ value: inputValue }),
headers: {
"Content-Type": "application/json"
}
};
let responsePost = await fetch("/post", options);
let myJsonPost = await responsePost.json();
document.getElementById("inputValue").value = myJsonPost.postval;
}
Both when you send JSON data via GET and POST, you must extract it with response.json(). In addition, when submitting POST data, you must set a header that is JSON. Without it, the server will not recognize that the transmitted data is in this format.

Related

Handlebars handler for dropdown onchange event not working

I'm using Express with Handlebars for front-end. When the selected option in the dropdown in home.handlebars changes, I want to trigger an event and read the value of the selected option in index.js. As I understand, I should use a Handlebars helper for this. I created a helper server.js (the Node.js backend) and added it to the onchange event for the dropdown. However, the handler does not seem to work. Here is my code:
server.js:
const express = require('express');
const app = express();
const handlebars = require('express-handlebars');
const port = 3000;
app.use(express.static('public'));
var handlebarsHelpers = handlebars.create({
helpers: {
dropdownChange: function (value) {
console.log("helper running.");
console.log("value is " + value);
return value;
}
}
});
app.engine('handlebars', handlebarsHelpers.engine);
app.set('view engine', 'handlebars');
app.set('views', './views');
app.get('/', (req, res) => {
res.render('home', {layout: false});
});
<...>
app.listen(port, () => {
console.log(`Server listening on port ${port}`)
});
index.js:
import * as d3 from "https://cdn.skypack.dev/d3#7";
import axios from 'https://cdn.skypack.dev/axios';
const dataSet = async function getData() {
return await axios.get('/data');
}
var courseData = [];
function getNodes() {
//************************getNodes is the function that should eventually read the dropdown value************************
}
async function drawGraph() {
const data = await dataSet();
console.log(data);
courseData = data.data;
console.log(courseData);
}
drawGraph();
home.handlebars:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Graph Chart</title>
</head>
<body>
<h2 align="center">Graph Chart</h2>
<div>
<select name="select" id="select" onchange={{dropdownChange value}}>
<option value="">Select a course...</option>
<option value="course1">course1</option>
<option value="course2">course2</option>
</select>
</div>
<svg class="prereq-graph"></svg>
</body>
</html>
<script type="module" src="./static/js/index.js"></script>
How do I fix the issue of the Handlebars helper not working? Alternatively, are there other ways to pass the dropdown selected value from Handlebars to Express when the onchange event is triggered?
Thank you.
Nevermind, I remembered that Javascript's addListener is a thing and solved my issue 🙃

Node.js send input text to python script for processing and writing the output on a div on the same page

I am trying to take text from an HTML input field and send it via POST-request to a python script for processing (I am using child process).
Right now, I am just sending the processed data to the response and overwriting the index.html, but I would like to just write the output of the python script into a text field under the input field in the same endpoint ("/").
Is there a way of doing this without having to re-render the entire HTML with just the new text added to it?
server.js:
const express = require("express");
const { spawn } = require("child_process");
const path = require("path");
const bodyParser = require("body-parser");
const router = express()
const app = express();
const port = 3000;
app.use(bodyParser.urlencoded({extended:true}));
app.get("/", (req, res) => {
res.sendFile(path.join( __dirname+'/index.html'));
});
app.post("/", (req, res) => {
// This is where the text field data is parsed into the python script
const python = spawn("python", ["script.py", req.body.sentence]);
python.stdout.on("data", function (data) {
processed_data = data.toString();
});
python.stderr.on("data", data => {
console.error(`stderr: ${data}`);
})
python.on("exit", (code) => {
// Something else here possibly?
res.send(processed_data);
});
})
app.listen(port, () => console.log(`App listening on port ${port}!`));
index.html:
<form method="POST" action="/">
<fieldset>
<label>Write a sentence:</label>
<input type="text" id="sentence" name="sentence" required>
<br><br>
<button type ="submit">Run</button>
<br><br>
<textfield id=output_field><textfield>
</fieldset>
</form>
script.py can really do anything here:
import sys
sentence = sys.argv[1]
print(sentence , " this is stuff added to the sentence")
sys.stdout.flush()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<fieldset>
<label>Write a sentence:</label>
<input type="text" id="sentence" name="sentence" required>
<br><br>
<button id='buttonFetch'>Run</button>
<br><br>
<textfield id="output_field"><textfield>
</fieldset>
<script>
const button = document.querySelector("#buttonFetch")
button.addEventListener("click", () => {
const sentence = document.querySelector("#sentence").value
fetch("http://localhost:3000/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
sentence
}),
})
.then(res => res.text())
.then(data => {
console.log(data)
const output_field = document.querySelector("#output_field")
output_field.textContent = data
})
.catch(e => {
console.error(e.error)
})
})
</script>
</body>
</html>
server.js (I removed bodyParser and add express.json())
'use strict'
const express = require("express");
const { spawn } = require("child_process");
const path = require("path");
//const bodyParser = require("body-parser");
const router = express()
const app = express();
const port = 3000;
app.use(express.json())
//app.use(bodyParser.urlencoded({extended:true}));
app.get("/", (req, res) => {
res.sendFile(path.join( __dirname+'/index.html'));
});
app.post("/", (req, res) => {
console.log(`req.body.sentence: ${req.body.sentence}`)
// This is where the text field data is parsed into the python script
const python = spawn("python", ["script.py", req.body.sentence]);
let processed_data = ''
python.stdout.on("data", function (data) {
processed_data = data.toString();
});
python.stderr.on("data", data => {
console.error(`stderr: ${data}`);
})
python.on("exit", (code) => {
// Something else here possibly?
console.log(processed_data)
res.send(processed_data);
});
})
app.listen(port, () => console.log(`App listening on port ${port}!`));

Can't store my new generated data in MongoDB

I am building a small project where you can generate a random hex color and then save it to database. But I don't know what I am doing wrong because my data won't save to database.
So index.js is my main file where I am declaring routes. I am using ejs for templeting and a separate file in a public folder where I write my javascript code. Can you give me a hint? Should I somehow work on my JS file where I click the button to submit the hex code somewhere?
index.js
const express = require('express');
const app = express();
const path = require('path');
const mongoose = require('mongoose');
const Color = require('./models/hexColor');
mongoose.connect('mongodb://localhost:27017/randColor', {useNewUrlParser: true, useUnifiedTopology: true})
.then(() => {
console.log("MONGO CONNECTION OPEN")
})
.catch(err => {
console.log("ERROR MONGO CONNECTION")
console.log(err)
})
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use('/public', express.static('public'));
app.use(express.urlencoded({extended: true}));
app.get('/home', (req, res) => {
res.render('homepage.ejs')
})
app.get('/hexColor', async (req, res) => {
const color = await Color.find({});
res.render('hexColor.ejs', { color });
})
app.post('/hexColor', async (req, res) => {
const newColor = new Color(req.body)
await newColor.save();
})
app.listen(3000, () => {
console.log("Listening!")
})
hexColor.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../public/hexColor.css">
<title>Hex Color Generator</title>
</head>
<body>
<form action="/hexColor" method="POST">
<div class="nav-container">
<div>
<h4 class="back-to-home">Home</h4>
</div>
<div>
<h1>Hex Color Generator</h1>
</div>
<div>
<h4>History</h4>
</div>
</div>
<div class="btn-container">
<button class="btn-generator">Click to generate</button>
</div>
<div class="color-container">
<div class="square-container">
</div>
</div>
<ul class="hex"></ul>
</form>
<script src="../public/hexColor.js"></script>
</body>
</html
hexColor.ejs
const homeBtn = document.querySelector(".back-to-home");
const btnGenerator = document.querySelector(".btn-generator");
const squareCont = document.querySelector(".square-container");
const ul = document.querySelector('.hex');
function hexChangeColor () {
var randomColor = Math.floor(Math.random()*16777215).toString(16);
var hexColor = `#${randomColor}`;
return hexColor;
}
homeBtn.addEventListener('click', function () {
window.location.href = 'http://localhost:3000/home'
})
btnGenerator.addEventListener('click', function (e) {
e.preventDefault();
squareCont.style.backgroundColor = hexChangeColor();
const li = document.createElement('LI');
li.innerHTML = hexChangeColor();
ul.appendChild(li);
})
hexSchema.js
const mongoose = require('mongoose');
const colorSchema = new mongoose.Schema({
hex: {
type: String
}
})
const Color = mongoose.model('Color', colorSchema);
module.exports = Color;
what you are getting in req.body?
Try by adding body-parser
https://www.npmjs.com/package/body-parser

Cross-Origin Request Blocked (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://localhost:3000/’)

I was recently trying to understand how CORS works, so I setup 2 local servers
to check if I can cross send data between them
localhost:3000 looks like this:
const express = require('express');
const app=express();
app.use(express.json());
app.get('/',(req,res)=>{
res.sendFile('public/index.html',{root:__dirname})
});
app.listen(process.env.PORT || 3000,()=>{
console.log('Listening at Port 3000...');
});
and it's index.html looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="others()">get Others data</button>
<script>
function others(){
fetch('http://localhost:3100/',{
method: "POST",
headers: {'Access-Control-Allow-Origin':'http://localhost:3000/'},
body: JSON.stringify({stat:'good'})
})
.then(function(res){ return res.json(); })
.then(function(data){ console.log(JSON.stringify( data ) ) })
}
</script>
</body>
</html>
localhost:3100 looks like this:
const express = require('express');
const cors = require('cors')
const app=express();
app.use(express.json());
app.use(cors({
origin: 'http://localhost:3000/'
}));
app.post('/',(req,res)=>{
res.json({data:"data from 3100 server!"});
});
app.listen(process.env.PORT || 3100,()=>{
console.log('Listening at Port 3100...');
});
but when I run the 2 servers simultaneously and make the fetch from localhost:3000 it shows this error:
I'm a bit new to this can someone please explain what I'm doing wrong?
Remove the / at the end of origin.
It'll work because there is a difference between http://localhost:3000 and http://localhost:3000/.
Trailing slash when accessing a file will always look for index file.
So, instead of this:
app.use(cors({
origin: 'http://localhost:3000/'
}));
Use this:
app.use(cors({
origin: 'http://localhost:3000'
}));

how to pass variable from nodejs to html directly without using pug?

I need to pass a variable from a NodeJS file to a rendered html file. How to do that?
Here below what I had tried
Nodejs code
const loginRouter= express.Router();
const config= require('../config/config.json');
loginRouter.get('/', (req,res)=>{
res.render(path.dirname(__dirname)+'/views/login.html',{version:config.version});
//res.json('done')
});
HTML Code
<label style="font-size:10px;float: right;"><%= version %></label>
Current Result:-
Nothing is coming
Expected Result:-
<label style="font-size:10px;float: right;">3.9</label>
I have set this version number in my config which I have imported in my login.js, but still, I am not getting the output. Does anyone have any idea about it?
If you don't want to use a templating engine like ejs or pug then you can just send a get request with axios or fetch to your node server and send a response.
Here's a sample on how you can do it. Change it according to your needs.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1 id="title">My page</h1>
<script>
fetch('http://localhost:5000/version').then(function(response) {
return response.json();
}).then(function(myJson) {
document.getElementById('title').innerHTML = myJson;
});
</script>
</body>
</html>
server.js
const express = require('express');
const app = express();
const PORT = 5000;
app.get('/', (req, res) => {
res.sendFile('index.html', {root: __dirname });
});
app.get('/version', (req, res) => {
const myVersion = 'My version is 0.5';
res.json(myVersion);
});
app.listen(PORT, () => {
console.log(`Server running on PORT ${PORT}`);
});

Categories

Resources