I'm getting empty request body in express.js - javascript

I'm trying to get my data in my database but not getting anything in the body of the request. I have used parse-body and CORS but it still not working.
I tried several things but did not work.
Backend code:
const bodyParser = require('body-parser');
const cors = require('cors');
const port = 5000;
const app = express();
app.use(cors());
app.use(bodyParser.json());
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb+srv://ishadDB#cluster0.gi4fd.mongodb.net/?retryWrites=true&w=majority";
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
client.connect((err) => {
const bookings = client.db("BurjAlArab").collection("bookings");
console.log("Connected");
app.post('/addBooking', (req, res) => {
console.log(req)
const newBooking = req.body;
console.log(newBooking);
bookings.insertOne(newBooking)
.then(res => {
res.send(result.insertedCount > 0);
});
});
});
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port);
front end:
const handleBooking = () => {
const newBooking = { ...loggedInUser, ...selectedDate };
fetch('http://localhost:5000/addBooking', {
method: 'POST',
header: { 'Content-Type' : 'application/json' },
body : JSON.stringify({newBooking})
})
.then((res) => res.json())
.then((data) => {
console.log(data);
});
};
Can anyone help me out?

Try to send it in your frontend with the following code
This take use of await
Notice because of the use of await the function have to be async
async function bla(){}
async function bla(){
const data = {newBooking};
const options = {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data)
};
await fetch('/addBooking', options);
}
}

Related

Express fetching data promise is pending

I've written 2 snippets of code - client and server. When the client clicks the button he sends information to the server, which uses the Riot API to retrieve summoner info. Now I want to send it back to the client but once I fetch it my promise response is pending and result is undefined. Promises are a new thing for me. Here's the code,
Client:
<!DOCTYPE html>
<html>
<head>
<script>
function sendInfo(){
let name = document.getElementById("checker").value;
let data = {name};
fetch("/api", {
method: "POST",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(data)
});
//let data = document.getElementById("levelID");
fetch("/level", {
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(function(res){
console.log(res.json());
})
.then(function(data){
console.log(data);
})
.catch(function(error){
console.log(error);
});
}
</script>
</head>
<body>
<input type="text" name="checkPlayer" id="checker"><br>
<button onclick="sendInfo()">Search summoner!</button>
</body>
</html>
Server:
const PORT = 3000;
const axios = require("axios");
const express = require("express");
const path = require('path');
const key = "RGAPI-50e38ac8-4629-4abc-aef9-68e4259448bd";
const parser = require("body-parser");
var jsonParser = parser.json();
//let puuid, summonerID, level;
let summoner;
const app = express();
app.listen(PORT, () => {
console.log("listening at 3000");
});
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, '/main.html'));
//searchBySummonerName("RnkzOnFire");
});
app.post("/api", jsonParser, (req, res) => {
searchBySummonerName(req.body.name);
});
app.get("/level", (req, res) => {
res.writeHead(200, {"Content-Type": "application/json"});
res.write(JSON.stringify(summoner));
});
function searchBySummonerName(name){
const searchURL = "https://eun1.api.riotgames.com/lol/summoner/v4/summoners/by-name/" + name + "?" + "api_key=" + key;
axios.get(searchURL).then((res) => {
summoner = res.data;
});
}

Getting 404 Not Found when trying to access Node/Express endpoint from client

I have a Node.js/Express REST API I have made to be accessed by a front end React app for an inventory management system to use for a garage sale. When trying to add a new Product, I try to access the POST route http://localhost:3001/api/new. However, when I try to access it, it retures a 404 Not Found error, despite being confident that I've done what has to be done for the route to be seen to the server, in order for the client to be able to fetch it. Could anyone shed some light on what I might be missing if anyting?
Accessing the endpoint from the client:
const addNewItemHandler = async () => {
setIsLoading(true);
const REQUEST_BASE_URL = "http://localhost:3001";
const REQUEST_ROUTE = "/api/new";
const REQUEST_URL = `${REQUEST_BASE_URL}${REQUEST_ROUTE}`;
const REQUEST_CONFIG = {
method: "POST",
body: JSON.stringify({
"productID": productID,
"name": productName,
"quantity": quantity,
"price": parseFloat(`${priceDollar}.${priceCents.split("")[0]}${priceCents.split("")[1]}`)
}),
headers: {
'Content-Type': 'application/json'
}
};
try {
await fetch(REQUEST_URL, REQUEST_CONFIG);
setIsLoading(false);
const currentItems = JSON.parse(localStorage.getItem('all-items'));
const newItem = {
id: productID,
title: productName,
quantity: quantity,
price: parseFloat(`${priceDollar}.${priceCents.split("")[0]}${priceCents.split("")[1]}`)
};
localStorage.setItem('all-items', JSON.stringify([...currentItems, newItem]));
history.push('/');
} catch (err) {
console.error(err);
setIsLoading(false);
}
};
server.js:
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const sequelize = require('./db-config');
const apiRoutes = require('./routes/APIRoutes');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
);
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
next();
});
app.use('/api', apiRoutes);
sequelize.sync().then(result => {
app.listen(3001, console.log("Staring on port 3001"));
}).catch(error => {
console.error(error);
});
APIRoutes.js
const express = require('express');
const router = express.Router();
const controller = require('../controller/Controller');
router.get('/all-items', controller.allitems);
router.get('/search/:term', controller.search);
router.get('/summary', controller.viewSummary);
router.post('/api/new', controller.createNewProduct);
router.patch('/sell-item', controller.sellProduct);
router.delete('/delete-all', controller.deleteAllProducts);
router.delete('/delete/:id', controller.deleteProduct);
module.exports = router;
Controller.js
const Sequelize = require('sequelize');
const Product = require('../models/Product');
const SoldProduct = require('../models/SoldProduct');
const Op = Sequelize.Op;
const allItems = (request, response) => {
// ...
};
const search = (request, response) => {
// ...
};
const viewSummary = (request, response) => {
// ...
};
const createNewProduct = (request, response) => {
const { productID, name, quantity, price } = request.body;
Product.create({
productID: productID,
name: name,
quantity: quantity,
price: price
}).then(() => {
response.json({ message: "Successfully created a new product" });
}).catch(error => {
response.json({ message: "Something went wrong" });
});
};
const sellProduct = (request, response) => {
// ...
};
const deleteAllProducts = (request, response) => {
// ...
};
const deleteProduct = (request, response) => {
// ...
};
exports.allitems = allItems;
exports.search = search;
exports.viewSummary = viewSummary;
exports.createNewProduct = createNewProduct;
exports.sellProduct = sellProduct;
exports.deleteAllProducts = deleteAllProducts;
exports.deleteProduct = deleteProduct;
In server.js file, you mount all the routes in APIRoutes.js file to /api path:
app.use('/api', apiRoutes);
With this configuration, the URL should be: http://localhost:3001/api/api/new.
You can mount your routes to '/' path, then you can access your routes like you did.
app.use('/', apiRoutes);
or in the APIRoute.js file, you change from /api/new to just /new
router.post('/new', controller.createNewProduct);

How to increment property in MongoDB collection using $inc

I have a list of articles that have a property views and I want to increment that property in the database each time a user clicks on an article title. Currently nothing happens when I do it. Why isn't it working and how can I increment that property each time on click? Here is my React part:
const incrementViews = (id) => {
var item = posts.find(x => x._id === id);
item.views += 1;
}
<div className="post-title">
<Link to={`/post/${post._id}`}>
<h2><a href="#" onClick={() => incrementViews(post._id)}>{post.title}</a>
</h2>
</Link>
</div>
and my server.js:
// Requiring the dependencies
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
require('dotenv').config();
const mongoose = require('mongoose');
const PORT = process.env.PORT || 3001;
const BASE_URL = process.env.REACT_APP_BASE_URL;
console.log(BASE_URL)
const itemRoutes = express.Router();
let Comment = require('./comment.model');
app.use(cors());
app.use(bodyParser.json());
mongoose.connect(BASE_URL, { useNewUrlParser: true })
const connection = mongoose.connection;
connection.once('open', function () {
console.log('Connection to MongoDB established succesfully!');
});
let collection = connection.collection("posts_with_tags_test");
collection.createIndex(
{
postContent: 'text',
title: 'text'
}
);
// Serve static assets
if (process.env.NODE_ENV === 'production') {
app.use(express.static('build'));
}
itemRoutes.route('/').get(async (req, res) => {
let collection = connection.collection("posts_with_tags_test");
let response = await collection.find({})
.toArray();
res.send(response);
});
itemRoutes.route('/search').post(async (req, res) => {
let result = await connection.collection("posts_with_tags_test").find({
$text: {
$search: req.body.searchString
}
}).toArray();
res.send(result);
});
itemRoutes.route("increment/:id"").post(async (req, res) => {
const { id } = req.params;
collection.updateOne({ _id: id }, { $inc: { views: 1 } });
return res.status(200).json({ msg: "OK" });
});
itemRoutes.route('/comments').get(async (req, res) => {
let collection = connection.collection("comments");
let response = await collection.find({})
.toArray();
res.send(response);
});
itemRoutes.route('/comments')
.post((req, res) => {
res.setHeader('Content-Type', 'application/json');
let comment = new Comment(req.body);
comment.save()
.then(comment => {
res.status(200).json({ comment })
})
.catch(err => {
res.status(400).send('failed')
})
});
app.use('/', itemRoutes);
app.use('/comments', itemRoutes);
app.use('/search', itemRoutes);
app.use('/increment', itemRoutes);
app.listen(PORT, function () {
console.log('Server is running on' + ' ' + PORT);
})
I think there are two problems in frontend and backend respectively.
Front-end
You should use post variable as a state variable so as to re-render then component when changes are made on post.
Back-end
There is no issue with increasing view in your code.
Here, you need to return success status.
The function incrementViews only increments views on the frontend and never sends any data to the API. One way you can make it work is as follows:
server.js
itemRoutes.route("/increment/:id").post(async (req, res) => {
const { id } = req.params;
collection.updateOne({ _id: id }, { $inc: { views: 1 } });
return res.status(200).json({ msg: "OK" });
});
React
const incrementViews = (id) => {
// Assuming your API server is running on port 5000.
fetch(`http://localhost:5000/increment/${id}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((res) => res.json())
.then(console.log)
.catch(console.error);
};
Update
The reason you're getting 404 is a missing colon : in the route parameters.
// Notice the :id, colon is important.
itemRoutes.route("/increment/:id").post(async (req, res) => {
const { id } = req.params;
// ...
});
Here is a demo reproduced on Glitch. Removed database logic and just added a response messages.
I tested the demo using Postman and it works fine.
On a POST request to https://adaptive-sassy-legal.glitch.me/increment/123, should return a response as shown below.
{
msg: "itemsRoute increment.",
id: "123"
}
Update 2
Another thing which I forgot to mention in the previous update was to update the middleware.
// Use only `/increment` instead of `increment/:id`.
app.use("/increment", itemRoutes);
Here is an updated demo.

node js TypeError: Cannot read property 'body' of undefined

I'm working on an example project for a Udacity course and I'm tripped up with something. I'm trying to capture some user input from a form and make a post request to return a javascript object and when I try to run the server with node js, I get the error:
TypeError: Cannot read property 'body' of undefined
This is the server code for the project:
server.js
projectData = {};
/* Express to run server and routes */
const express = require('express');
/* Start up an instance of app */
const app = express();
/* Dependencies */
const bodyParser = require('body-parser')
/* Middleware*/
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const cors = require('cors');
app.use(cors());
/* Initialize the main project folder*/
app.use(express.static('project1'));
const port = 8000;
/* Spin up the server*/
const server = app.listen(port, listening);
function listening(){
// console.log(server);
console.log(`running on localhost: ${port}`);
};
// GET route
const animalData = [];
app.get('/all', getData);
function getData(req, res){
res.send(AnimalData)
console.log(AnimalData)
}
// function sendData (request, response) {
// response.send(projectData);
// };
// POST route
app.post('/add', callBack);
function callBack(req,res){
res.send('POST received');
}
// POST an animal
const data = [];
// TODO-Call Function
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(addAnimal())
function addAnimal(req, res){
newEntry = {
animal: req.body.animal,
facts: req.body.fact,
fav: req.body.fav
}
data.push(req.body);
res.status(200).send(req.body);
animalData.push(newEntry)
res.send(animalData)
console.log(animalData)
};
and this is the code for the client side:
app.js
function performActuion(e){
const fav = document.getElementById('fav').value;
const getAnimal = async (url) =>{
const res = await fetch(url);
try {
const data = await res.json();
console.log(data)
return data;
} catch(error) {
console.log()
}
};
/* Function to POST data */
const postData = async ( url = '', data = {})=>{
console.log(data);
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
const newData = await response.json();
console.log(newData);
// console.log(newData);
return newData.json()
console.log(await response.json());
return await response.json()
}catch(error) {
console.log("error", error);
// appropriately handle the error
};
};
// TODO-Call Function
(async function(){
let res = await postData('/addAnimal', (animal: data.animal, fact: data.fact, fav: fav));;
console.log(res);
})();
In the example for the lesson, this code appears to work but when I try to run it on my end I can't even test it because I get that type error. Any help would be greatly appreciated.
Thank you,
Mike
The problem is in this code:
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(addAnimal())
You are actually calling the function instead of use it as callback, use the following code:
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(addAnimal)

Why is the Query from getInitialProps empty?

I want to fetch some data using query parameters on the server for a page.
However, my query is empty inside getInitialProps when rendered through server. Why could this be happening?
Moreover, I have noticed this only happens in production server and not in the dev or prod env on my local.
Here's some code
import React from 'react';
import Config from 'component/Config';
import { withAuthSync } from 'util/auth';
import apiUrl from 'util/apiUrl';
function ResourceConfigPage({ data }) {
return <Config data={data} />;
}
ResourceConfigPage.getInitialProps = async ctx => {
const { resourceId } = ctx.query;
try {
const response = await fetch(`${apiUrl}/resource/config?resourceId=${resourceId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
});
if (response.ok) {
const data = await response.json();
return { data };
}
}
return {};
};
export default withAuthSync(ResourceConfigPage);
My next app uses a custom express server and here's how it looks.
const express = require('express');
const next = require('next');
const compression = require('compression');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
const server = express();
app.setAssetPrefix(dev ? '' : 'https://example.com');
server.use(compression());
server.get('/healthcheck', (req, res) => {
res.status(200).json({});
});
server.get('/', (req, res) => {
if (req.cookies.sessionId) {
res.redirect('/dashboard');
}
res.redirect('/login');
});
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(3000, err => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});

Categories