Create simple form submission web page in React, Express and MongoDB

Create simple form submission web page in React, Express and MongoDB

Here we will show how to create simple MERN stack (MongoDB, Express, React, Node) web application that has submission form.
Once we submit the data, frontend will initiate POST query fia axios library to the backend API endpoint. Express backend will be listening for such query and will save the data into MongoDB database.

This simple fullstack app can be used a a basic template for other more complex projects.

How to setup simple react frontend and backend

First, make sure you have node, npm and npx installed

$ node -v
v18.12.1
$ npm -v
8.19.2
$ npx -v
8.19.2 

Create basic directory structure

coil@coil-VM:~/Desktop$ tree -L 1 chat_GPT/
chat_GPT/
├── backend
├── frontend
└── markdown_article.md

2 directories, 1 file
coil@coil-VM:~/Desktop$ 

Frontend

First create frontend with create-react-app command.

coil@coil-VM:~/Desktop/chat_GPT/frontend$ npx create-react-app .

Creating a new React app in /home/coil/Desktop/chat_GPT/frontend.

Install axios library for the API calls.

coil@coil-VM:~/Desktop/chat_GPT/frontend$ npm install axios

added 3 packages, and audited 1471 packages in 4s

create-react-app utility will add lots of files we do not need. Under src directory remove all files, keep only App.js and index.js and remove their contents as well, so they are empty files. Additionally create Form.js file under the same directory, this file will contain our React component with form that we will use to submit data to the database.

index.js just imports our React app and the App.js is used to import our React components, in our case Form component that is injected with self closing tag <Form /> in the JSX syntax.

index.js contents:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

App.js contents:

import Form from './Form';

function App() {
  return (
    <div>
      <header>
        <p>Example form.</p>
      </header>
      <Form />
    </div>
  );
}

export default App;

Form.js contents:

import React, { useState } from 'react';
import axios from 'axios';

function Form() {

  const port = 5000;

  const [formData, setFormData] = useState({});

  const handleChange = (event) => {
    setFormData({
      ...formData,
      [event.target.name]: event.target.value
    });
  }

  const handleSubmit = (event) => {
    event.preventDefault();

    axios.post(`http://localhost:${port}/api/endpoint`, formData)
      .then((response) => {
        console.log(response.data);
      })
      .catch((error) => {
        console.error(error);
      });
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" name="name" onChange={handleChange} />
      </label>
      <br />
      <label>
        Email:
        <input type="email" name="email" onChange={handleChange} />
      </label>
      <br />
      <button type="submit">Submit</button>
    </form>
  );
}

export default Form;

Start the frontend with npm start command.

Backend

Backend is based on Express and Mongoose that will handle connection to MongoDB.

API will be listening for POST query payload and will save the data into the database.

Express backend will need to use cors library, otherwise web browser will reject connection to the backend endpoint due to CORS (Cross-Origin Resource Sharing) issue since it will evaluate our backend as not trustworthy. More info about CORS and Express https://expressjs.com/en/resources/middleware/cors.html.

coil@coil-VM:~/Desktop/chat_GPT/backend$ npm install express mongoose cors

added 159 packages, and audited 160 packages in 21s

For backend we will need just one file called app.js and we will run it with node app.js command.

app.js contents:

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const bodyParser = require('body-parser');

const app = express();
const port = 5000;

mongoose.set('strictQuery', false);

// Connect to the MongoDB database
mongoose.connect('mongodb://localhost:27017/gpt_test_db', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

const connection = mongoose.connection;

connection.once('open', () => {
  console.log('MongoDB connection established successfully');
});

connection.on('error', (error) => {
  console.error(error);
});

// Create a Mongoose model for the data
const FormData = mongoose.model('FormData', {
  name: String,
  email: String
});

app.use(cors());
app.use(bodyParser.json());

// POST request handler for the API endpoint
app.post('/api/endpoint', (req, res) => {
  // Create a new FormData object with the request body data
  const formData = new FormData(req.body);

  // Save the form data to the database
  formData.save()
    .then(() => {
      res.send('Successfully saved form data to the database');
    })
    .catch((error) => {
      console.error(error);
      res.send('Error saving form data to the database');
    });
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

Database

We will use MongoDB as our database.
Installation of MongoDB is out of scope of this article since installation process varies based on your OS, moreover there are issues running specific versions of MongoDB in VirtualBox in certain cases, since some CPU flags are not correctly passed to the VM. Best would be running the database out of a Docker container and then just mount the volume with the data to our local file system. For more details refer to mongodb official container documentation in docker hub: https://hub.docker.com/_/mongo.

Once we send our POST query from frontend to the backend, we should see new data in our database.

We used database model called FormData, MongoDB automatically converted it to formdatas collection under our db since it always makes the plural form of our model name.

// Create a Mongoose model for the data
const FormData = mongoose.model('FormData', {
  name: String,
  email: String
});
coil@coil-VM:~/Desktop$ mongo
MongoDB shell version v4.4.18
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
MongoDB server version: 4.4.18

> show dbs
gpt_test_db       0.000GB
> use gpt_test_db
switched to db gpt_test_db
> show collections;
formdatas
> db.formdatas.find({})
{ "_id" : ObjectId("63af0d6d4c9197376f2a83e4"), "name" : "John Doe", "email" : "john.doe@email.com", "__v" : 0 }
> 

At this point our demo app should be fully functional, you can check the POST payload in the web browser after pressing F12 and clicking on the Network tab in the dev tools inspector.

The boiler plate code was generated by Chat GPT (https://chat.openai.com/chat), only minor changes were required to make the demo work locally. Interesting is that it forgot to add CORS, but once it was instructed to do so, it generated the demo code with CORS support as well. AI assistants are capable of significantly reducing development time, at least for short demo projects.

Sources