Post request sends null value to the database POSTGRESQL react node - node.js

When I am making a post request from react, it sends a null value to the database.
So, I put log statements everywhere and it seems that : on the server side in nodejs, the const {firstName} is undefined and I do not understand why. Also, I log the req on the server-side and the body is empty body:{}.
Client side: when I put log statement in try block on body, it log me this: firstName: "abc" . So, the POST method does receive the body, but I do not understand where it gets lost?
When I console.log the state, it does set the state to the input value. However, when it sends data, the value is null.
I am using the following Reactjs, Nodejs, aws-rds-postgresql.
This is sever-side in nodejs
app.post("/users", async (req, res) => {
try {
const {firstName} = req.body;
console.log({firstName})
const newUser = await pool.query(
"INSERT INTO users (firstname) VALUES ($1) RETURNING *",
[firstName]
);
res.json(newUser.rows[0]);
}catch (err) {
console.log(err.message);
}
});
This is client side in react:
const CreateEmployee = (props) => {
const [firstName, setEmployeeForm] = useState("");
const onSubmitForm = async (event) => {
event.preventDefault();
try {
const body = {firstName};
console.log(body);
const response = await fetch("http://localhost:5000/users", {
method: "POST",
headers: {"Content-Type": "application/json"},
// We convert the React state to JSON and send it as the POST body
body: JSON.stringify(body)
});
console.log(response);
} catch (err) {
console.log(err.message);
}
}
return (
<Fragment>
<h1 className="text-center mt-5">PernTodo</h1>
<form className="d-flex mt-5" onSubmit={onSubmitForm}>
<input type="text" className="form-control" value={firstName} onChange={e=> setEmployeeForm(e.target.value)}/>
<button className="btn btn-success">Add</button>
</form>
</Fragment>
);
}
export default CreateEmployee;

I found the answer.
The issue was with the order of body-parser;
The order must be as follows with bodyParser on the very top.
const bodyParser = require('body-parser');
const express = require("express");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

Adding this line in nodejs worked for me:
app.use(express.json())

Related

Axios post request not working React Nodejs Mongodb

I am trying to post a data to the mongoose database but I keep getting Axios error 404. I need help. Is there something wrong in my code?
This is my modal, it contains the front end of the website
AddForm.jsx
import React, { useState } from "react";
import axios, { Axios } from "axios";
const AddForm = () =>{
const [appData, setAppData] = useState({
pName:"",
appNum:"",
datetime:"",
})
const submit =(e) =>{
e.preventDefault();
axios.post("/addAppDetails", {
pName: appData.pName,
appNum: appData.appNum,
datetime: appData.datetime,
})
.then(res =>{
console.log(res.appData)
})
.catch((error)=>{
console.log(error);
});
}
const handle = (e) => {
const newData={...appData}
newData[e.target.id] = e.target.value
setAppData(newData)
console.log(newData)
}
return(
<Form onSubmit={(e) => submit(e)}>
<Form.Group>
<Form.Control
id="pName"
type="text"
placeholder="Patient Name"
onChange={(e) => handle(e)}
value={appData.pName}
required/>
</Form.Group>
<Form.Group>
<Form.Control
id="appNum"
type="text"
placeholder="Appointment Number"
onChange={(e) => handle(e)}
required/>
</Form.Group>
<Form.Group>
<Form.Control
id="datetime"
as="textarea"
placeholder="Date and Time"
onChange={(e) => handle(e)}
required/>
</Form.Group>
<Button variant="success" type="submit" block>Update Appointment</Button>
</Form>
)
}
export default AddForm;
This is my backend, it contains the route/api for functionality
server.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const cors = require("cors");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
app.use(express.json()); //prints body request
app.use(cors());
const JWT_SECRET = "sdaikdhjiIHDiu8987J(#?!dDSF8645DAsadA[]ds54aASD()21asd1SFP";
const mongooseURL =
"mongodb+srv://client:lolpassword#cluster0.lfrgaha.mongodb.net/?retryWrites=true&w=majority";
//server
app.listen(5001, () => {
console.log("Server started successfully.");
});
//connect with DB
mongoose
.connect(mongooseURL, {
useNewUrlParser: true,
})
.then(() => {
console.log("Connected to database successfully");
})
.catch((e) => console.log(e));
require("./models/appointmentDetails");
const AppDetails = mongoose.model("AppointmentDetails");
//add data to db
app.post("/addAppDetails", async(req, res) => {
const newAppDetails = new AppDetails(req.body);
try{
newAppDetails.save();
res.send(newAppDetails);
}
catch(err){
console.log(err);
res.status(500).send(error);
}
});
This is my database model.
appointmentDetails.js
const AppDetails = new mongoose.Schema(
{
pName: String,
appNum: String,
datetime: String,
status: String,
action: String,
},
{
collection: "AppointmentDetails",
}
);
mongoose.model("AppointmentDetails", AppDetails);
404 means the url (including http://host:port) that you are using to send request & expecting response from, doesn't exist in your case.
While sending request, check if your node server is receiving the response or not, using logs, or a global middleware function logging every request info. This way you'll see whether the server is receiving the request or not, and thus find the problem.
As suggested in the answer by #thillon (now deleted probably), most likely in your case the url is incomplete (doesn't contain the server's host:port part), so you can follow their way to ensure that your request url is proper and thus make sure that your server is able to receive request is this particular case.
Global middleware function
Write this right after your app.use(express.json()) statement.
app.use((req, res, next) => {
console.log(req.body)
// or log anything helpful in the req object
next();
})

req.files is undefined using express-fileupload

I am creating a blog so, wanted to upload an image for each post. I used express-file upload for this purpose. Using nodejs I have done the following to save the image sent from the client-side in MongoDB. When I print the value of req.files in the console I get undefined.
exports.addPost = (req, res) => {
const file = req.files.file
const post = new Blog()
post.title = req.body.title
post.des = req.body.des
post.file = file
post.save((err, doc) => {
if (!err) {
res.send(doc)
} else {
console.log(err)
}
})
}
In react I have Addpost.js that sets the state and handles the form submit as follows:
const Addpost=()=> {
const [title, settitle] = useState('')
const [des, setdes] = useState('')
const [file, setfile] = useState('');
const {addPost}=useContext(Globalcontext)
const handleSubmit = (e)=>{
e.preventDefault()
const formData = new FormData()
formData.append('file',file)
const addedValue={
title,
des,
formData
}
addPost(addedValue)
settitle('')
setdes('')
setfile('')
}
const onChange=(e)=>{
const file=e.target.files[0]
setfile(file)
}
return (
<div>
<form onSubmit={handleSubmit} encType="multipart/form-data">
<input type="text" name="title" value={title} onChange={(e)=>settitle(e.target.value)}/>
<input type="text" name="des"value={des} onChange={(e)=>setdes(e.target.value)}/>
<input type="file" name="file" onChange={onChange}/>
<button type='submit' value='submit'>Add Post</button>
</form>
</div>
)
}
The AXIOS post request is sent as:
function addPost(postdetail) {
axios.post('http://localhost:4000/blog', postdetail).then(res => {
dispatch({
type: 'ADD_DATA',
payload: res.data
})
}).catch(error => {
console.log(error)
})
}
I am getting the error:
Cannot read property 'file' of undefined
1. Probably you didn't register middleware.
According to the doc example, you should register express-fileupload middleware before you refer req.files:
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
// default options
app.use(fileUpload());
Also don't forget to add null check in case when no files are uploaded:
app.post('/upload', function(req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
let file = req.files.file;
// do something with uploaded temp file
}
2. Content type should be multipart/form-data when you upload file
const handleSubmit=(e)=>{
e.preventDefault()
const formData=new FormData()
formData.append('file', file)
setfile('')
}
function addPost(postdetail){
axios.post('http://localhost:4000/blog',formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res=>{
dispatch({
type:'ADD_DATA',
payload:res.data
})
}).catch(error=>{
console.log(error)
})
}
3. Other form fields(des, title) may not be submitted using multipart/formdata
Consider open two routes for blog creation.
[POST] '/blog/upload-image' for image upload
[POST] '/blog/new for create blog (title, des and image_id acquired from image upload response)

Express server posting twice, exactly two minutes apart?

I am trying to build a react chat box using an express server and pusher to listen for a dialogflow bot. It works fine at first, but the bot always responds a second time, repeating itself (but sometimes with a different response) exactly two minutes later to the second.
I have some logging statements in the server code to try and debug it, and have been monitoring the react front-end for network activity. It appears that react is only sending one fetch request, because there is only one network log in the browser. But on the server-side, the request is logged twice. I'm not sure why this is or what I'm doing wrong!
// server.js
require("dotenv").config({ path: "variables.env" });
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const processMessage = require("./process-message");
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post("/chat", (req, res) => {
const { message } = req.body;
processMessage(message);
console.log(message);
});
app.set("port", process.env.PORT || 5000);
const server = app.listen(app.get("port"), () => {
console.log(`Express running → PORT ${server.address().port}`);
});
//process-message.js
const Dialogflow = require("dialogflow");
const Pusher = require("pusher");
const projectID = "firstchatbox-fakeURL";
const sessionID = "123456";
const languageCode = "en-US";
const config = {
credentials: {
private_key: process.env.DIALOGFLOW_PRIVATE_KEY,
client_email: process.env.DIALOGFLOW_CLIENT_EMAIL
}
};
const pusher = new Pusher({
appId: process.env.PUSHER_APP_ID,
key: process.env.PUSHER_APP_KEY,
secret: process.env.PUSHER_APP_SECRET,
cluster: process.env.PUSHER_APP_CLUSTER,
encrypted: true
});
const sessionClient = new Dialogflow.SessionsClient(config);
const sessionPath = sessionClient.sessionPath(projectID, sessionID);
const processMessage = message => {
const request = {
session: sessionPath,
queryInput: {
text: {
text: message,
languageCode
}
}
};
sessionClient
.detectIntent(request)
.then(responses => {
console.log(responses);
const result = responses[0].queryResult;
return pusher.trigger("bot", "bot-response", {
message: result.fulfillmentText
});
})
.catch(err => {
console.error("ERROR:", err);
});
};
module.exports = processMessage;
// Here is the React front-end code, even though i'm ~60% sure
//the bug is server-side at this point
//App.js
import React, { Component } from "react";
import Pusher from "pusher-js";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
userMessage: "",
conversation: []
};
}
componentDidMount() {
const pusher = new Pusher("fakepusherappID454564564566", {
cluster: "us3"
});
const channel = pusher.subscribe("bot");
channel.bind("bot-response", data => {
const msg = {
text: data.message,
user: "ai"
};
this.setState({
conversation: [...this.state.conversation, msg]
});
});
}
handleChange = event => {
this.setState({ userMessage: event.target.value });
};
handleSubmit = event => {
event.preventDefault();
if (!this.state.userMessage.trim()) return;
const msg = {
text: this.state.userMessage,
user: "human"
};
this.setState({
conversation: [...this.state.conversation, msg]
});
fetch("http://localhost:5000/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
message: this.state.userMessage
})
})
.then(d => console.log(d))
.catch(e => console.log(e));
this.setState({ userMessage: "" });
};
render() {
const ChatBubble = (text, i, className) => {
return (
<div key={`${className}-${i}`} className={`${className} chat-bubble`}>
<span className="chat-content">{text}</span>
</div>
);
};
const chat = this.state.conversation.map((e, index) =>
ChatBubble(e.text, index, e.user)
);
return (
<div>
<h1>React Chatbot</h1>
<div className="chat-window">
<div className="conversation-view">{chat}</div>
<div className="message-box">
<form onSubmit={this.handleSubmit}>
<input
value={this.state.userMessage}
onInput={this.handleChange}
onChange={this.handleChange}
className="text-input"
type="text"
autoFocus
placeholder="Type your message and hit Enter to send"
/>
</form>
</div>
</div>
</div>
);
}
}
export default App;
It shows occasional console errors:
Source map error: TypeError: NetworkError when attempting to fetch resource.
Resource URL: http://localhost:3000/static/js/0.chunk.js
Source Map URL: 0.chunk.js.map
but I don't think they are relevant?
Exactly two minutes apart sounds like it could be a browser request that timed out and the browser is retrying.
And, now that I look at your app.post() handler, you don't seem to send any sort of response back to the client so that could cause an issue like this.
All http requests received by your server must send some sort of response, even if they just send a 404 or 500 status back. Either do res.sendStatus(200) or res.send("some response");.
You can open the debugger in Chrome and look at the network tab and then submit your form and watch exactly what network traffic happens between client and server.
And, since you tried this and it fixed your problem, I'm posting it as an answer.

Making POST request to SQL Server through React

I am trying to make a simple textbox entry form for the user to type their first and last name, then click submit. I'd like the data to be updated in my SQL Server. Whenever I try to make a request I get the error
Unexpected token S in JSON at position 0
This is the code I am using:
server.js:
var express = require('express');
var app = express();
var sql = require("mssql");
var config = {
user: 'username',
password: 'password',
server: 'localhost',
database: 'Master'
};
app.post('/', function(req, res) {
res.set('Access-Control-Allow-Origin', '*');
var user = req.body;
var connection = new sql.ConnectionPool(config, function(err) {
var request = new sql.Request(connection);
request.query('INSERT INTO Persons SET ?', user);
});
res.end('Success');
});
app.listen(5000, () => {console.log('Server is running..')});
And here is the code from react:
import React, { Component } from 'react';
class postData extends Component {
constructor() {
super();
this.state = { user: {} };
this.onSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
var self = this;
// On submit of the form, send a POST request with the data to the server.
fetch('http://localhost:5000', {
method: 'POST',
data: {
FirstName: self.refs.FirstName,
LastName: self.refs.LastName
}
})
.then(function(response) {
//this is the line that is giving me the error
return response.json()
}).then(function(body) {
console.log(body);
});
}
render() {
return (
<form onSubmit={this.onSubmit}>
<input type="text" placeholder="First Name" ref="FirstName"/>
<input type="text" placeholder="Last Name" ref="LastName"/>
<input type="submit" />
</form>
);
}
}
export default postData;
I am getting the error from the react side. Not sure how to set this up. Any ideas where I might be screwing up? Thanks!!!
The data that your react app is passing to express is just the raw text. Try adding body-parser to your express app, and then deconstructing the values that are passed in. You could manually parse the body into JSON format, but it would be much easier to include body-parser. body-parser also allows you to parse the body of your request into other formats as well if you wish.
Add body-parser to your express app:
const bodyParser = require('body-parser');
app.use(bodyParser.json());
Then in your POST request, deconstruct the body like like this:
const { firstName, lastName } = req.body;
let connection = new sql.ConnectionPool(config, function(err) {
let request = new sql.Request(connection);
request.query(/* Your query to insert these values */);
});
res.end('Success');
Usually, you get that error because the response is a string instead of a JSON object. Try changing your express:
res.send({ message: 'Success'})
I'n not sure that you're using refs correctly either. I might try putting those values in state with an on change function:
handleChange = (e) => {
this.setState(
{
[e.target.name]: e.target.value
}
)
}
And change your inputs to:
<input type="text" placeholder="First Name" name="FirstName" onChange={this.handleChange}/>
Then in your submit function:
FirstName: this.state.FirstName
Hope that helps

How can I retrieve search results with only one click of the search button instead of two?

I am working on a Node.js + ElasticSearch + React.js project and I have managed to get the search to work! However, I have to click the search button twice before I get back results in my console. Eventually, I would like to output the results via components to the user. any input would be great!
Here is React.js:
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
state = {
result: [],
name: 'Roger',
userInput: null,
}
handleSubmit = event=> {
event.preventDefault();
var input = document.getElementById("userText").value;
this.setState({ userInput: input });
axios.get('http://localhost:4000/search?query=' + this.state.userInput)
.then(res => {
var result = res.data;
this.setState({ result: result });
console.log(this.state.result);
console.log(this.state.userInput);
})
}
render() {
return (
<div className="App">
<h2>hello from react</h2>
<form action="/search">
<input type="text" placeholder="Search..." name="query" id="userText"/>
<button type="submit" onClick={this.handleSubmit}><i>Search</i></button>
</form>
</div>
);
}
}
export default App;
here is Node.js:
const express = require('express');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const JSON = require('circular-json');
const PORT = 4000;
var client = require ('./connection.js');
var argv = require('yargs').argv;
var getJSON = require('get-json');
const cors = require('cors');
let app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors({
origin: 'http://localhost:3001',
credentials: true
}));
app.get('/', function(req, res){
res.send("Node is running brother");
});
app.get("/search", function (request, response) {
client.search({
index: 'club',
type: 'clubinfo',
body: {
query: {
match: { "name": query}
},
}
},function (error, data, status) {
if (error) {
return console.log(error);
}
else {
// Send back the response
response.send(data);
}
});
});
app.listen(PORT, () => console.log('wowzers in me trousers, Listening on port ' + PORT));
this.setState() is an asynchronous function, which means that the updated data will only be available in its callback.
To better show this, try with this modification:
handleSubmit = event=> {
event.preventDefault();
var input = document.getElementById("userText").value;
axios.get('http://localhost:4000/search?query=' + input)
.then(res => {
var result = res.data;
this.setState({ result: result, userInput: input }, () => {
console.log(this.state.result);
console.log(this.state.userInput);
});
})
}
Note: you are handling your "userText" field as an uncontrolled field. This means that you let it be filled by native html+js, and just get the content from the DOM. Doing this, you never really need to have a "userInput" state variable.
Here is a snippet with userText as a controlled field:
class App extends Component {
state = {
result: [],
name: 'Roger',
userInput: '',
}
handleChange = event=> {
event.preventDefault();
this.setState({userInput: event.target.value});
}
handleSubmit = event=> {
event.preventDefault();
axios.get('http://localhost:4000/search?query=' + this.state.userInput)
.then(res => {
var result = res.data;
this.setState({ result: result });
console.log(this.state.result);
console.log(this.state.userInput);
})
}
render() {
return (
<div className="App">
<h2>hello from react</h2>
<form action="/search">
<input type="text" value={this.state.userInput} onChange={this.handleChange} placeholder="Search..." name="query" id="userText"/>
<button type="submit" onClick={this.handleSubmit}><i>Search</i></button>
</form>
</div>
);
}
}
I believe you'd better implement onChange function on your input, so you would have actual user search request the moment he or she would type it in.
Take official react doc for this example
https://reactjs.org/docs/forms.html
The reason it takes two times for the button to be pushed is that (may be) your state would become familiar with search request only after first push, and then you need second to actually get axios to send request (because it is null on first one)

Resources