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

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

Related

How to wait for GET Request with Axios to complete

I am making a Web-Notepad using Nodejs and express where all the data is gonna be saved in MongoDB. I want to grab the data through my Rest API making an HTTP request with Axion.
When I send the GET request, the program doesn't wait for the JSON file, continues and because of that, it exports an undefined file with the site is getting shown without the data.
With the console.log after the GET request, I get all the data I need - but too late.
app.js:
const express = require('express');
const chalk = require('chalk');
const debug = require('debug')('app');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv/config')
const app = express();
const port = 3000;
app.use(cors());
app.use(express.static('views'));
app.use(bodyParser.json());
app.set('views', './views');
app.set('view engine', 'ejs');
const postsRoute = require('./routes/posts');
// Here i import the data from the GET request
const getData = require('./routes/router');
app.use('/posts', postsRoute);
// The outcome of this log is; Promise {<pending>}
console.log(getData);
app.get('/', (req, res) => {
res.render(
'index',
{
// Here i want to send the Data to the ejs file
getData,
title: 'Notepad'
});
});
// Connect to DB
mongoose.connect(
process.env.DB_CONNECTION,
{useUnifiedTopology: true, useNewUrlParser: true, useCreateIndex: true, useFindAndModify: false}, () =>
debug('Connected correctly to MongoDB')
);
app.listen(port, () => {
debug(`Listening on port ${chalk.green(port)}`);
});
router.js where i make the GET request (i should change the name of the file...)
const axios = require('axios').default;
async function getData() {
try {
const response = await axios.get('http://localhost:3000/posts');
console.log(response);
return response.data
} catch (err) {
console.log(err);
}
}
module.exports = getData();
GET Request:
router.get('/', async (req, res) => {
try {
const posts = await post.find();
res.json(posts);
} catch (err) {
res.json({message: err})
}
});

How to set different bodyparser on specific express route

I am using express 4.
in my server.js I have express.json() middleware
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');
const errorHandler = require('./_helpers/error-handler');
const app = express();
const port = process.env.PORT || 5000;
app.use(cors());
app.use(express.json()); /////////////////////////////////////////
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: true});
const connection = mongoose.connection;
connection.once('open', () => {
console.log("MongoDB database connection established successfully");
});
// routers
app.use('/api/users', require('./routes/api/users/users.controller'));
app.use('/api/orders', require('./routes/api/orders/orders.controller'));
app.use('/shopify/app', require('./routes/shopify/app/shopify.controller'));
app.use('/shopify/app/webhooks', require('./routes/shopify/app/webhooks/webhooks.controller')); ///////////////
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
but for '/shopify/app/webhooks' route I need to get raw body so I can create hash
but so far I am receiving Object because I have express.json() middleware.
this is my webhooks.controller.js file
const express = require('express');
const router = express.Router();
const crypto = require('crypto')
const SHOPIFY_API_SECRET_KEY = process.env.SHOPIFY_API_SECRET_KEY;
// router.use(express.raw({ type: "application/json"}));
// routes goes here
router.post('/app/uninstalled', express.raw({ type: 'application/json' }), async (req, res, next) => {
const hmac = req.get('X-Shopify-Hmac-Sha256')
console.log(req.body);
// create a hash using the body and our key
const hash = crypto
.createHmac('sha256', SHOPIFY_API_SECRET_KEY)
.update(req.body, 'utf8', 'hex')
.digest('base64')
// Compare our hash to Shopify's hash
if (hash === hmac) {
// It's a match! All good
console.log('Phew, it came from Shopifify!')
res.sendStatus(200)
} else {
// No match! This request didn't originate from Shopify
console.log('Danger! Not from Shopify!')
res.sendStatus(403)
}
})
what I have tried is in webhooks.controller.js router.use(express.raw({type: "application/json"}))
i thought since I am receiving json object I can use express.raw() middleware that accepts json
but it's still not working.
You have to place this route BEFORE your app.use(express.json()) middleware and then you can apply the raw middleware directly to that route:
app.use('/shopify/app/webhooks', express.raw({/* put your options here */}), require('./routes/shopify/app/webhooks/webhooks.controller'));
Keep in mind that this line of code must go physically before your express.json() middleware.
We can get useful info for specific routes before applying body parser.
So, if you want to get raw body for stripe webhooks.
We can do like this.
app.use(bodyParser.json({
extended: true,
verify: function (req, res, buf) {
if (req.originalUrl.endsWith('/stripe/webhooks')) {
req.rawBody = buf
}
}
}))

node.js post method req.body undefined even with body-parser

Hello guys I am working with node js to use dialogflow chat bot ,
I am trying to get parameters from http request post methode
I used postman for that and yes I did set up the content type to json in the header , I have the following code for my request body :
{
"text":"hello"
}
and the following link
http://localhost:5000/api/df_text_query
I have the following index.js file :
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
require('./routes/dialogFlowRoutes')(app);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }))
app.get('/',(req , res)=>{
res.send({'hello':'Johnny'});
});
const PORT = process.env.port || 5000;
app.listen(PORT);
this my dialogflowRoutes.js file :
const dialogflow = require('dialogflow');
const config = require('../config/keys');
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = sessionClient.sessionPath(config.googleProjectID, config.dialogFlowSessionID);
module.exports = app => {
app.get('/', (req, res) => {
res.send({ 'hello': 'world!' })
});
app.post('/api/df_text_query', async (req, res) => {
console.log(req.body)
const request = {
session: sessionPath,
queryInput: {
text: {
text: req.body.text,
languageCode: config.dialogFlowSessionLanguageCode
}
}
};
let responses = await sessionClient
.detectIntent(request);
res.send(responses[0].queryResult)
});
app.post('/api/df_event_query', (req, res) => {
res.send({ 'do': 'event query' })
});
}
this is the error I get when I send the following request
dialogFlowRoutes.js:17
text: req.body.text,
^
TypeError: Cannot read property 'text' of undefined
Order in which you initialize middleware matters.
You must parse body before you act on it. Move your routing middleware after you initialize bodyParser, like below:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }))
require('./routes/dialogFlowRoutes')(app);

CORS issue with Express Router end points

I have a react app that is making a REST to a an express node server.
The express router defines a bunch of rest endpoints.
When I hit the endpoints in the express router using postman, it works fine.
When I hit the endpoint with me react app, it doesn't. I'm seeing 400 error when my react app makes the call using axios.
This is what my index.js looks like:
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const passport = require("passport");
const cors = require("cors");
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
// server.use(bodyParser.json());
app.use(cors());
// app.options("*", cors());
const UserModel = require("./models/User");
mongoose
.connect(
"mongodb"
)
.then(() => console.log("SUCESSFULLY connected to MongoDB!"))
.catch((error) => console.log(`FAILED tot connect to MongoDB: ${error}`));
require("./auth/localStrategyAuth");
const authRoutes = require("./routes/authRoutes");
app.use("/v1", authRoutes);
// app.post("/", (req, res) => {
// res.send("Hello World!");
// });
// app.post("/v1/signup", (req, res) => {
// console.log("lol");
// });
// app.use(express.json());
const PORT = 5000;
app.listen(PORT, () =>
console.log(`ui-rest listening on port localhost:${PORT}`)
);
user.js
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const { Schema } = mongoose;
const UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
});
const UserModel = mongoose.model("user", UserSchema);
module.exports = UserModel;
authRoutes.js
const express = require("express");
const passport = require("passport");
const jwt = require("jsonwebtoken");
const JWTstrategy = require("passport-jwt").Strategy;
//We use this to extract the JWT sent by the user
const ExtractJWT = require("passport-jwt").ExtractJwt;
const router = express.Router();
// When the user sends a post request to this route, passport authenticates the user based on the
// middleware created previously
router.post(
"/signup",
passport.authenticate("signup", { session: false }),
async (req, res, next) => {
res.json({
message: "Signup successful",
user: req.user,
});
}
module.exports = router;
localStrategyAuth.js
const passport = require("passport");
const localStrategy = require("passport-local").Strategy;
const UserModel = require("../models/User");
//Create a passport middleware to handle user registration
passport.use(
"signup",
new localStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
// Save the information provided by the user to the the database
const user = await UserModel.create({ email, password });
// Send the user information to the next middleware
return done(null, user);
} catch (error) {
done(error);
}
}
)
);
This is what my express router looks like:
const express = require("express");
const router = express.Router();
router.post(
"/signup",
passport.authenticate("signup", { session: false }),
async (req, res, next) => {
res.json({
message: "Signup successful",
user: req.user,
});
}
);
module.exports = router;
What am I missing? I've set up CORS in the index.js file. I just can't see where I'm going wrong. Why cant my react app hit the express router endpoints.
If I have a normal express endpoint, then my react app is able to hit those endpoints. For example, the endpoint below works fine when my react app hits it.
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
app.post("/", (req, res) => {
res.send("Hello World!");
});
const PORT = 5000;
app.listen(PORT, () =>
console.log(`listening on port localhost:${PORT}`)
app.post("/someSignup", (req, res) => {
console.log("signup");
});
I've also tried things like with no luck:
const authRoutes = require("./routes/authRoutes");
authRoutes.use(cors());
Here is what my react code looks like when it submits the rest call:
// axios setup
axios.create({
baseURL: "http://localhost:5000",
// headers: {
// "Content-Type": "application/json",
// },
});
// Handle submit
handleSubmit = async (event) => {
event.preventDefault();
const newUserData = {
// firstName: this.state.firstName,
// lastName: this.state.lastName,
email: this.state.email,
password: this.state.password,
};
const result = await axios.post("/v1/signup", newUserData);
console.log(result);
};
Here is a screenshot of headers tab on chrome console
Here is a screenshot of response tab on chrome console
Here is a screenshot of the request
400 means bad request, your problem isn't about with cors.
You didn't setup your api to handle JSON data which react sends, so it can't read your request.body and gives 400-Bad Request.
So you need to add this line:
app.use(bodyParser.json());
Also in the current versions of express, body parser isn't required , it comes with express. So you can use it like this:
app.use(express.json());
The reason it worked with postman is that you sent the data in x-www-form-urlencoded.
you can use check my code for cors error.
const express = require('express');
var mongoose = require('mongoose');
const bodyParser = require('body-parser');
var morgan = require('morgan');
var cors = require('cors')
const app = express();
// CORS Middleware
app.use(cors());
// Logger Middleware
app.use(morgan('dev'));
// Bodyparser Middleware
app.use(bodyParser.json());
const MongoClient = require('mongodb').MongoClient;
const uri = "uri";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
client.connect(err => {
console.log('MongoDB Connected...')
const collection = client.db("dbname").collection("collectionname");
app.post('/name', (req, res) => {
collection. insertOne({ name: req.body.name })
res.send("data added")
});
});
const port = process.env.PORT || 5000;
app.listen(port, function () {
console.log(`Example app listening on port ${port}`);
});
You need to register the cors middleware into express app.
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
app.use(cors());
app.post("/", (req, res) => {
res.send("Hello World!");
});
const PORT = 5000;
app.listen(PORT, () => console.log(`listening on port localhost:${PORT}`)

JS Fetch posts only object ID to localhost

When I send form data using fetch, only the _id is registered in my database.
Using postman to post does send the correct data to the database. Also, the fetch posts to another server on heroku fine (I don't know how that server has been set up unfortunately).
With postman I've tried setting the Header content type to x-www-form-urlencoded, when that didn't solve the problem, I set the content type to json. That also did not work. The body Content-Type is set to x-www-form-urlencoded.
Using fetch to get the data from the express server (which has cors enabled) works fine. The data is also being correctly logged, so I'm pretty sure it's something with the post request....
sendToServer () {
console.log(this.state)
fetch(`http://localhost:3000`, {
method: "post",
headers: {
// also tried with 'application/json'
'Accept': 'application/x-www-form-urlencoded',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: JSON.stringify(this.state)
})
}
Maybe this adds more clarity, the object I'm expecting is
{
"_id": "59adb44602416d102c095260",
"title":"meetup",
"date":"2017-09-06T00:00:00.000Z",
"venue":"starbucks"
}
But instead I'm getting:
{
"_id": "59adb44c02416d102c095261"
}
The server code:
//index.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
const db = require('./db');
const router = require('./router');
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(router);
app.listen(3000, ()=>{
console.log('express app listening on port 3000')
})
//router.js
const express = require('express');
const router = express.Router();
const controller = require('./controller')
router.get('/', controller.getAll)
router.post('/', controller.create)
module.exports = router;
//controller.js
const mongoose = require('mongoose');
const EventModel = require('./model');
const getAll = async (req, res) => {
res.send(await EventModel.find());
}
const create = async (req, res) => {
const newEvent = EventModel({
title: req.body.title,
date: req.body.date,
venue: req.body.venue,
});
await newEvent.save();
res.send(newEvent);
}
module.exports = {getAll, create};
//model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Event = new Schema({
title: String,
date: Date,
venue: String,
}, {versionKey: false});
const EventModel = mongoose.model('Event', Event);
module.exports = EventModel;
//db.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/cw-events', {useMongoClient: true});
mongoose.Promise = global.Promise;
mongoose.connection.on('connected', () => {
console.log('Mongoose connected')
})
I realised that my problem was that I'd formatted the body-parser to parse requests from postman which were url-encoded. All I had to do was change it to json, so:
//from this
app.use(bodyParser.urlencoded({ extended: false }));
//to this
app.use(bodyParser.json());
So now it parses json format, which is what the fetch is posting.

Categories