Cannot POST to Express router (404 error) - javascript

I cannot fetch POST requests to my Express router. I have many GET requests which work fine, but this is my first POST request and it is not working.
My frontend code looks like this:
export async function postHamster(name, age) {
try {
await fetch('/hamsters/api/new-hamster',
{
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: name,
age: age
})
})
console.log("postHamster has run") //LOGGED
}
catch (e) {
console.error(e)
}
}
The response will always be:
fetchData.js:38 POST http://localhost:3000/hamsters/api/new-hamster 404 (Not Found)
I have triple-checked the path and it cannot be in error. The backend path is "router.get('api/new-hamster', async (req, res)..." in the file 'hamsters.js'.
I have also put the backend function at the very top of its file, to ensure that it is not overrruled by any other function in the file.
This is my server.js:
// THIS FIRST FUNCTION I JUST COPIED FROM A SOLUTION BUT IT DOES NOT SEEM TO HELP
// routes/index.js
module.exports = (express) => {
// Create express Router
var router = express.Router();
// add routes
server.route('/hamsters/api/new-hamster')
.post((req, res) => {
res.setHeader('Content-Type', 'application/json');
res.send('You sent: sdadad to Express');
});
return router;
}
const express = require('express');
const server = express();
const serverPort = process.env.PORT || 1234;
server.use(express.static(__dirname + '/../build'))
let data = require('./data.json')
const { Router } = require('express');
let router = new Router();
//USE BODY-PARSER BEFORE REGISTERING ROUTES!
const bodyParser = require('body-parser')
server.use(bodyParser.urlencoded({ extended: true }));
server.use(bodyParser.json())
server.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// ROUTES
const hamstersRoute = require('./routes/hamsters');
const chartsRoute = require('./routes/charts')
const gamesRoute = require('./routes/games')
const statsRoute = require('./routes/stats')
const imagesRoute = require('./routes/images')
const uploadRoute = require('./routes/upload')
server.use('/assets', express.static("assets"))
server.use(express.static('public'))
server.use('/hamsters', hamstersRoute)
server.use('/charts', chartsRoute)
server.use('/games', gamesRoute)
server.use('/stats', statsRoute)
server.use('/images', imagesRoute)
server.use('/upload', uploadRoute)
server.listen(serverPort, () => {
console.log(`Server is up n running on port ${serverPort}!`)
})
module.exports = data;
I have looked at these threads:
Cannot GET/POST with express Router()
Express.js routers post request returns 404
Express: router cannot read POST request

Have you checked the url you're trying to post to in the network tab in the console? I think you need to add a / before api in the backend route: router.get('/api/new-hamster', async (req, res)...".

You have this:
server.use(bodyParser.urlencoded({ extended: true }));
Instead of this:
server.use(bodyParser.urlencoded({ extended: false }));

Related

req.body returning empty object when sending POST request from client side javascript

This post is hidden. You deleted this post 1 min ago.
Hi their are many questions related to the same topic but none of them solved my problem thats why asking new question
What I wanted to do is to send POST request from client side javascript to the Backend NodeJs
Client Side JS
const verifyOtp = async (otp) => {
const res = await fetch("http://127.0.0.1:3000/api/otpVerify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ otp: otp.value }),
});
const data = await res.json();
console.log(data);
}
Backend Node js
const verifyOtp = router.post("/api/otpVerify", (req, res, next) => {
const otp = req.body;
console.log("Otp recieved: ", otp);
console.log("Actual Otp: ", req.session.otp);
if (otp == req.session.otp) {
return res.json({ isVerified: true });
}
return res.json({ isVerified: false });
});
App.js File
const express = require("express");
const bodyParser = require("body-parser");
const path = require("path");
const session = require("express-session");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(
session({ secret: "cezisbest", resave: false, saveUninitialized: false })
);
app.use(express.static(path.join(__dirname + "public")));
app.set("view engine", "ejs");
app.set("views", "views");
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type, application/json"
);
next();
});
app.use("/api", userRoutes);
app.listen(process.env.PORT);
what I am getting Backend Node js file is an empty object Please help me with this error
opt.value is having a value which it is getting from frontend
in client side JS
on browser chrome it is displaying an object
{isVerified:false}
because the backend is unable to get data
Please help me with this issue
You are not setting the req.session.otp value before calling /api/otpVerify. What is the reason you are using req.session?
req.session is basically gets cookies related information
Refer this:
Cannot access req.session variables in Express/NodeJS

Cors error in client when calling mongodb database from backend

I am having a problem with cors when I call my netlify hosted nodejs express backend from my react frontend.
im am getting the following errormessage in my web browser:
Access to XMLHttpRequest at 'https://<my_api_domain>/api/forgotpassword' from origin 'localhost:8888' has been blocked by CORS policy: No 'Access-
Control-Allow-Origin' header is present on the requested resource."
I have tried a lot of solutions with setting headers in the respons from my backend, but nothing seams to work. In localhost everything works fine.
the main file, api.js, looks like this:
'use strict';
const express = require('express');
const serverless = require('serverless-http');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const router = express.Router();
router.use(express.json());
const apiLimiter = require('../middleware/ratelimiter');
//import modules
const youtube = require('./youtube');
const ip = require('./ip');
const sendgrid = require('./sendgrid');
const sendinblue = require('./sendinblue');
const login = require('./login');
const forgotPassword = require('./forgotpassword');
const register = require('./register');
const test = require('./test');
require('dotenv').config();
router.use(helmet());
router.use(morgan('combined'));
router.use(cors());
//this part was added in order to try to fix the cors error
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization'
);
res.setHeader(
'Access-Control-Allow-Methods',
'GET, POST, PUT, DELETE, PATCH, OPTIONS'
);
next();
});
app.use(bodyParser.json());
router.use('/ip', ip);
router.use('/youtube', youtube);
router.use('/sendgrid', sendgrid);
router.use('/sendinblue', sendinblue);
router.use('/login', login);
router.use('/register', register);
router.use('/test', test);
router.use('/forgotpassword', forgotPassword);
app.use('/api', router);
// path must route to lambda
app.set('trust proxy', 1);
module.exports = app;
module.exports.handler = serverless(app);
The cors error only happens when I call the forgotpassword endpoint, which looks like this:
const express = require('express');
const router = express.Router();
//const { check, validationResult } = require('express-validator');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const connect = require('../functions/db');
const captcha = require('../middleware/captcha');
const sendMail = require('../functions/sendResetMail');
require('dotenv').config();
// get usermodel
const User = require('../models/User');
const Token = require('../models/resetPassword');
//#path: /forgotpassword
//# public
router.post(
'/',
captcha,
async (req, res) => {
const { email } = req.body.data;
console.log(email);
connect();
try {
// See if user exists
const user = await User.findOne({ email });
if (!user) {
console.log('no user'); //fjernes
return res.status(200).json({
errors: [{ msg: 'If user Exists, an email will be sendt' }],
});
}
const extToken = await Token.findOne({ userId: user._id });
if (extToken) {
await extToken.deleteOne();
}
const payload = {
user: {
id: user._id,
},
};
const secret = process.env.JWT_RESET_PASSWORD;
const webToken = jwt.sign(payload, secret, {
algorithm: 'HS256',
expiresIn: 3600,
});
const salt = await bcrypt.genSalt(10);
const tokenHash = await bcrypt.hash(webToken, salt);
const token = new Token({
userId: user._id,
token: tokenHash,
});
await token.save();
res
.status(200)
.header('Access-Control-Allow-Origin', 'http://localhost:60427')
// several ways is tried of the above
.json({ link: webToken, url: UrlLink });
return;
} catch (err) {
res.status(400).json({ errors: [{ msg: err }] });
return;
}
}
);
i have figured out that the cors error only appears if from either when I make a call to the database (not when connecting) og if I try to use crypt. If I don't make a cal to the database, or encrypt with bcryept, the cors error will not appear in my web browser.
PS: my frontend and backend is hosted separately, so the domain is not the same.
any help to figure this out will be much appreciated :)
I ran into this issue quite a bit I would make sure that you allow access at the very top of your server file so that its allowing access across all of your routes. Something like this
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use((_, res, next) => {
res.set('Access-Control-Allow-Origin', '*'); // or 'localhost:8888'
res.set('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
res.set(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
return next();
}); // sets headers before routes
// routes start here
app.use('/ip', ip);
app.use('/youtube', youtube);
Make sure that if you're setting the response headers you're doing so BEFORE all of your routes. Most of the times I've struggled with CORS is because I was only setting it on some routes some of the time. This setup will ensure every route is g2g.
You can mention the origins allowed as shown below
const cors = require('cors');
app.use(cors({
origin: ['http://localhost', 'https://localhost/']
}));
or for all origins
app.use(cors({
origin: '*'
}));
Solved!
Turnes out in this case, the error is misleading at best. I had forgotten to add the new environment variables (env. variables to connect to database, and to use JWT) to netlify for deployment. When that was done, it worked without changing any more code. PS: all code was changed according to the answers above.
Thank you to all the contributors :)
Why this resolved in a cors error in google chrome, I dont know. :)

Node.js REST endpoint not catching parameters passed from axios request

I'm making a POST request from a React front-end using axios to an endpoint to save some data to my DB (MongoDB). I'm getting an error that one cannot read property 'name' of undefined. I think that's occurring because req.body is undefined but I can't understand what's wrong with my axios request. I logged all the parameters and they are there (not undefined). The axios request and the endpoint are written below. Any help will be appreciated. Thanks!
Axios Request
const uploadElement = async (name, HTMLCode, JSCode, CSSCode, screenshot) => {
console.log(name)
try {
await axios({
method: 'post',
url: '/api/elements',
data: {
name: name,
HTMLCode,
JSCode,
CSSCode,
screenshot
}
});
} catch (e) {
console.log(e);
}
}
Endpoint for POST Request
router.post("/", upload.single("screenshot"), async (req, res) => {
try {
const newElement = new Element({
name: req.body.name,
JSCode: req.body.JSCode,
HTMLCode: req.body.HTMLCode,
CSSCode: req.body.CSSCode,
screenshot: req.file.buffer,
});
await newElement.save();
res.send("Data uploaded successfully!");
} catch (e) {
console.error(e);
}
});
Server.js
const express = require("express");
const passport = require("passport");
const session = require("express-session");
const cors = require('cors');
const elementRouter = require("./routes/elementRoute");
const authRouter = require("./routes/authRoute");
const connectDB = require("./config/db");
const app = express();
const port = process.env.PORT || 5000;
connectDB();
app.use(
session({
secret: "googleOAuth",
resave: false,
saveUninitialized: true,
})
);
app.use(cors());
// Passport Config
require("./config/passport")(passport);
app.use(passport.initialize());
app.use(passport.session());
app.use("/api/elements", elementRouter);
app.use("/api/auth", authRouter);
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});
You need to install and require body-parser in your serverside code
First run npm i --save body-parser
Then require it like this
const bodyParser = require("body-parser");
Then use it after you declare your app ( after this line const app = express();)
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
This makes the data of your request available in req.body

How to catch POST request on back-end?

<!doctype html>
<head>
</head>
<body>
<script>
const Http = new XMLHttpRequest();
const url='http://localhost:4550/users';
Http.open("POST", url);
Http.send("hey");
Http.onreadystatechange = (e) => {
console.log(Http.responseText)
}
</script>
</body>
</html>
//user.js
var express = require('express');
var router = express.Router();
var array = [];
/* GET users listing. */
router.get('/', (req, res, next) => {
res.send('respond with a resource1');
});
router.post('/', (req, res, next) => {
res.send('respond with a resource2');
});
module.exports = router;
//app.js
const express = require('express')
const app = express();
app.get('/',(req,res)=> {
console.log('lior');
res.send('api running 2')});
app.use('/users',require('./routes/users'))
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
const PORT = process.env.PORT || 4550;
app.listen(PORT,()=> console.log('server started on port ${PORT}'));
I am new with connecting client and server side, and it might be why I couldn't find an answer for my question. Is a simple question.
As you can see I want to send "hey" from the client to the server(user.js). However I don't know how does I catch the response on the server side.
I know that a "hey" or neither the code make much sense, but is just an example to make things simple, I just wondering how does the server side could catch and handle the data.
Thanks in advance!
When you post data, specify how you are encoding it. It's generally best to use a standard encoding method rather than POSTing plain text. (Also don't start variable names with capital letters unless they are constructor functions)
const http = new XMLHttpRequest();
const url = 'http://localhost:4550/users';
const data = JSON.stringify({ value: "hey" });
http.open("POST", url);
http.setRequestHeader("Content-Type", "application/json");
http.send(data);
http.onreadystatechange = (e) => {
console.log(http.responseText)
}
Then in your server side code, use a body parser to decode the data.
Since you are using an absolute URL in the request, it seems likely that you are making a cross-origin request so you also need to grant permission using CORS.
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()
const port = 4550
const jsonParser = bodyParser.json()
const corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200
};
const corsMiddleware = cors(corsOptions)
app.get('/', (req, res) => res.send('Hello World!'))
app.get('/users', (req, res, next) => {
res.send('respond with a resource1');
});
app.options("/users", corsMiddleware)
app.post('/users', corsMiddleware, jsonParser, (req, res, next) => {
// data is in `req.body` (which will have a `value` property because the object on the client does)
res.send('respond with a resource2');
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
(The above is untested and may have minor errors in it)
Please send serialized data as below:
const http = new XMLHttpRequest();
const url = 'http://localhost:4550/users';
const data = JSON.stringify("hey");
http.open("POST", url);
http.setRequestHeader("Content-Type", "application/json");
http.send(data);
You need to use bodyParser package
npm install body-parser
const bodyParser = require("body-parser");
and before setting up routes use it as below :
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
Don't forget to allow the headers declaration as below :
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST"
);
next();
});
and now you can read your data as below
router.post('/users', (req, res, next) => {
console.log(req.body);
});

Express get request empty

I would send data from angular to Express.
in my service ;
sendtext(text): Observable<any> {
console.log(text);
return this.http.post<string>(this.url, text, httpOptions);
}
I configure headers
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
my console.log(text) prints me the right text typed in an input.
In my server side I have created my server.js file
var http = require("http");
var admin = require('firebase-admin');
var firebase = require("firebase");
var express = require("express");
var app = express();
var routerProj = require("./routes/routes");
var bodyParser = require("body-parser");
var port = process.env.app_port || 8080; // set our port
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var server = app.listen(port);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,*");
next();
});
var config = {
......configuration...
};
firebase.initializeApp(config);
var serviceAccount = require("./ServiceAcountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://datatable-18f93.firebaseio.com"
});
app.use("/v1", routerProj);
//Create HTTP server and listen on port 8000 for requests
// Print URL for accessing server
console.log("Server running at http://127.0.0.1:8080/");
And I have created my router file:
var express = require("express"); // call express
var router = express.Router(); // get an instance of the express Router
var admin = require("firebase-admin");
router
.route("/")
.post(function (req, res, err) {
console.log(req.body);
// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("/");
// Attach an asynchronous callback to read the data at our posts reference
ref.push(
{
"text": req.body
}
);
});
module.exports = router;
Here console.log(req.body) prints an empty object {}
Is it because of the headers ? if yes how can I configure them ? I have already tried'Content-Type': 'application/json', and without headers, no result.

Categories