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
Related
I have created an API in Node js for file upload. It is working fine with the postman.
I made a form for uploading Excel files in Next Js. I can able to see selected files in the console.
But I am not able to set the file in formdata. I am getting empty form data in the console.
<div>
<input
class="form-control w-25"
multiple={false}
type="file"
id="ExcelFile"
onChange={uploadFile}
required
></input>
{/* </label> */}
<button
type="button"
// disabled={!selectedImage}
class="btn btn-primary "
>
ADD SOLUTION
</button>
</div>
const uploadFile = ({ target: { files } }) => {
console.log(files[0]);
// let data = new formData();
let FilesData = new FormData();
FilesData.append("excel_file", files[0]);
console.log("Files in multipart");
console.log(FilesData);
// data.append("file", files[0]);
};
https://codesandbox.io/embed/next-js-forked-th22n?fontsize=14&hidenavigation=1&theme=dark
If you try to console.log FormData object, you will just get empty object.Instead you should call the entries method on the FormData object.
for (const pair of FilesData.entries()){
console.log(pair)
}
It will return list of arrays of key-value pairs.
Notice that you can`t see your formData in console.log
If you want to pass data with formData you must use one middleware in your server like this: https://nextjs.org/docs/api-routes/api-middlewares
And i just use one example maybe be usefull:
in your formData:
var FormData = require("form-data");
let data = new FormData()
data.append("urlOrContent", urlOrContent)
and then send your formData in your server side
in your server side:
import middleware from "./middleware/middleware";
import nextConnect from "next-connect";
const handler = nextConnect();
handler.use(middleware);
handler.post(async (req, res) => {
//in formData: req.body.urlOrcontent[0]
try {
const response = await fetch(
req.body?.urlOrContent[0],
);
res.status(200).send({
data: {
message: "Success",
data: response.json(),
},
});
} catch (err) {
let e = {
func: "states.handler",
message: "خطای داخلی سرور رخ داده است!",
error: "Internal Server Error!",
code: 500,
};
res.status(500).json(e);
}
});
export const config = {
api: {
bodyParser: false,
},
};
export default handler;
Here's a little example on a simple form submission in next.js using multer to parse the form data.
Client
This is the client page, containing a super simple HTML form (can work without JS too)
// pages/my-form.ts
export default function Page() {
return (
<div>
<form id="data" method="post" action='/api/on-form-submit' encType="multipart/form-data">
<input name="title" label="Title"/>
<input name="video" label="Video"/>
<button type="submit">Submit</button>
</form>
</div>
);
};
Server
This is the server function that will receive the form submission.
// pages/api/on-form-submit.ts
import multer from "multer";
import { NextApiRequest, NextApiResponse } from "next";
async function parseFormData(
req: NextApiRequest & { files?: any },
res: NextApiResponse
) {
const storage = multer.memoryStorage();
const multerUpload = multer({ storage });
const multerFiles = multerUpload.any();
await new Promise((resolve, reject) => {
multerFiles(req as any, res as any, (result: any) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
return {
fields: req.body,
files: req.files
}
}
// IMPORTANT: Prevents next from trying to parse the form
export const config = {
api: {
bodyParser: false,
},
};
const Handler: NextApiHandler = async (req, res) => {
const result = await parseFormData(req, res);
console.log(result);
res.status(200).redirect('/success-page');
}
export default Handler;
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())
i have created a websites and deployed it ( using react js ) in my website there is a contact form which will send the client message to my work email ( myname#comany.com) . i know i can't send email with react js because rereact only handle the front end so i'm looking for a solution using nodemailer or other solutions ! how can i do that ?
i tried the following tutorials to link react with express : [https://medium.com/#maison.moa/setting-up-an-express-backend-server-for-create-react-app-bc7620b20a61][1]
i made a quick app for testing :
folder structure :
client ( created with create-react app )
node_modules
config.js
package.json
package_lock.json
server.js
in the front end : client/src
app.js code :
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Form from './Form.js';
class App extends Component {
state = {
data: null
};
componentDidMount() {
// Call our fetch function below once the component mounts
this.callBackendAPI()
.then(res => this.setState({ data: res.express }))
.catch(err => console.log(err));
}
// Fetches our GET route from the Express server. (Note the route we are fetching matches the GET route from server.js
callBackendAPI = async () => {
const response = await fetch('/express_backend');
const body = await response.json();
if (response.status !== 200) {
throw Error(body.message)
}
return body;
};
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<Form/>
<p className="App-intro">{this.state.data}</p>
</div>
);
}
}
export default App;
Email.js code :
import React from 'react';
import { Email, Item, A} from 'react-html-email';
export default function InlineLink({name, children}) {
return (
<Email title='link'>
<Item>
Hello {name}
<p>helooo</p>
</Item>
<Item>
{children}
</Item>
</Email>
)};
Form.js code :
import MyEmail from './Email'
import { renderEmail } from 'react-html-email'
import axios from 'axios';
import React, { Component } from 'react';
class Form extends Component {
resetForm(){
this.setState({feedback: ''});
}
constructor(props) {
super(props);
this.state = { feedback: '', name: 'Name', email: 'email#example.com' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<form className="test-mailing">
<h1>Let's see if it works</h1>
<div>
<textarea
id="test-mailing"
name="test-mailing"
onChange={this.handleChange}
placeholder="Post some lorem ipsum here"
required
value={this.state.feedback}
style={{width: '100%', height: '150px'}}
/>
</div>
<input type="button" value="Submit" className="btn btn--submit" onClick={this.handleSubmit} />
</form>
);
}
handleChange(event) {
this.setState({feedback: event.target.value})
};
handleSubmit(event){
const messageHtml = renderEmail(
<MyEmail name={this.state.name}> {this.state.feedback}</MyEmail>
);
axios({
method: "POST",
url:"http://localhost:3000/send",
data: {
name: this.state.name,
email: this.state.email,
messageHtml: messageHtml
}
}).then((response)=>{
if (response.data.msg === 'success'){
alert("Email sent, awesome!");
this.resetForm()
}else if(response.data.msg === 'fail'){
alert("Oops, something went wrong. Try again")
}
})
}
}
export default Form;
in the backend
server.js code :
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
// console.log that your server is up and running
app.listen(port, () => console.log(`Listening on port ${port}`));
// create a GET route
app.get('/express_backend', (req, res) => {
res.send({ express: 'YOUR EXPRESS BACKEND IS CONNECTED TO REACT' });
});
const nodemailer = require('nodemailer');
const creds = require('./config');
var transport = {
host: 'smtp.gmail.com', // e.g. smtp.gmail.com
auth: {
user: creds.USER,
pass: creds.PASS
}
}
var transporter = nodemailer.createTransport(transport)
transporter.verify((error, success) => {
if (error) {
console.log(error);
} else {
console.log('All works fine, congratz!');
}
});
app.use(express.json()); app.post('/send', (req, res, next) => {
const name = req.body.name
const email = req.body.email
const message = req.body.messageHtml
var mail = {
from: name,
to: 'mellitir11#gmail.com',
subject: 'Contact form request',
html: message
}
transporter.sendMail(mail, (err, data) => {
if (err) {
res.json({
msg: 'fail'
})
} else {
res.json({
msg: 'success'
})
}
})
})
config.js code :
module.exports = {
USER: 'mellitir11#gmail.com',
PASS: 'my_email_password',
}
even that it shows the error message which is "Oops, something went wrong. Try again"
[1]: https://medium.com/#maison.moa/setting-up-an-express-backend-server-for-create-react-app-bc7620b20a61
Please Refer the Below code , Which is working for me..
Paste the below Code in FrontEnd i.e React (app.js)
import React,{useState,useEffect} from "react"
import Axios from 'axios'
import './App.css';
function App() {
const [frommail,setfrommail]=useState("")
const [password,setpassword]=useState(0)
const [tomail,settomail]=useState("")
useEffect(()=>{
Axios.get("http://localhost:3001/read").then((response)=>{
console.log(response.data)
})
},[])
const sendmail=()=>{
Axios.post("http://localhost:3001/mail",{frommail:frommail,password:password,tomail:tomail}).then((response)=>{
if (response.data.msg === 'success'){
alert("Email sent, awesome!");
}else if(response.data.msg === 'fail'){
alert("Oops, something went wrong. Try again")
}
})
}
return (
<div className="App">
<label>From</label>
<input type="text" onChange={(e)=>{setfrommail(e.target.value)}}/>
<label>From Mail Password</label>
<input type="text" onChange={(e)=>{setpassword(e.target.value)}}/>
<label>To address</label>
<input type="text" onChange={(e)=>{settomail(e.target.value)}}/>
<input type="submit" onClick={sendmail}/>
</div>
);
}
export default App;
Then Here is the code For Backend i.e Node js
const express = require("express");
const app = express();
const cors=require('cors')
var nodemailer = require('nodemailer');
app.use(express.json());
app.use(cors())
app.post(("/mail"),async (req,res)=>{
const frommail=req.body.frommail
const password = req.body.password
const tomail=req.body.tomail
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: frommail,
pass: password
}
});
var mailOptions = {
from: frommail,
to: tomail,
subject: 'Sending Email using Node.js',
text: `sending mail using Node.js was running successfully. Hope it help you. For more code and project Please Refer my github page`
// html: '<h1>Hi Smartherd</h1><p>Your Messsage</p>'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
res.json({
msg: 'fail'
});
}
else{
res.json({
msg: 'success'
})
}
});
})
app.listen(3001, () => {
console.log("Server is Running");
});
Finally Ensure that your From mail id have a less secure app access:
check this feature is enable in your gmail account
Nodemailer might do the trick for you, in essence you will need an email account that supports smtp, node v6 or above and Nodemailer Documentation (there's a how to example) it supports ssl, Oauth authentication and DKIM. Depending on what you need specificly there are other options like mailgun and mailchimp that provide APIs or backend with PHP or Java
I am trying to submit a couple text boxes to my SQL database using React js through a post request, then on the server side I am listening for the post and querying the data to my database. Right now both values are returning "undefined" regardless of what the user inputs into the form, so I think I've screwed up the React side code. This is the code I am using
Server.js:
var express = require('express');
var app = express();
var sql = require("mssql");
const bodyParser = require('body-parser');
app.use(bodyParser.json());
var config = {
user: 'user',
password: 'pass',
server: 'localhost',
database: 'Master'
};
app.post('/', function(req, res) {
res.set('Access-Control-Allow-Origin', '*');
const { FirstName, LastName } = req.body;
let connection = new sql.ConnectionPool(config, function(err) {
let request = new sql.Request(connection);
request.query("insert into persons (FirstName, LastName) values ('" + FirstName + "', '" + LastName + "')");
});
res.send({ message: 'Success'})
});
app.listen(5000, () => {console.log('Server is running..')});
And here is my react code...
postData.js:
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',
body: {
FirstName: self.refs.FirstName,
LastName: self.refs.LastName
}
})
.then(function(response) {
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;
Again, I'm pretty sure I've screwed up the code on the React side, but I'm pretty new to all this so I'm not sure where to start troubleshooting. When I console.log the req.body on the server side it just returns {}, so it seems like there isn't any data being sent from the react script.
Thanks!
Thanks for all the help guys. I incorporated a lot of the recommendations you guys gave, but the final straw was the following in my server.js code
app.use(express.json({
type: ['application/json', 'text/plain']
}));
Once I included this change I was able to eliminate the undefined error I was getting
Add these lines on fetch request:
fetch('http://localhost:5000',
{ method: 'POST',
headers: new Headers({
"Content-Type":"application/json"
}),
body: JSON.stringify({
FirstName: self.refs.FirstName,
LastName: self.refs.LastName })
})
Then in your server
app.post('/', function(req, res) {
res.set('Access-Control-Allow-Origin', '*');
const body = JSON.parse(req.body);
let connection = new sql.ConnectionPool(config, function(err) {
let request = new sql.Request(connection);
request.query("insert into persons (FirstName, LastName) values ('" + body.FirstName + "', '" + body.LastName + "')");
});
res.send({ message: 'Success'})
});
Hope this helps.
To make your code work just replace this part:
body: {
FirstName: self.refs.FirstName,
LastName: self.refs.LastName
}
by this:
body: {
FirstName: self.refs.FirstName.value,
LastName: self.refs.LastName.value
}
but I would suggest you to do just like #Yousaf did, and use React.createRef(); to create refs to elements in React
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)