FullStack setup (Node.js, React.js and MongoDB)
Tags: node, express, react, mongodb
Published: 2019-07-04 20:26:07

---
title: FullStack setup (Node.js, React.js and MongoDB)
published: true
description: I decided to share my node environment from scratch. I hope you like it.
tags: Node, Express, React, MongoDB
cover_image: https://thepracticaldev.s3.amazonaws.com/i/xot85m5gezw3k6bpgycs.jpg
---


Whenever I have to create a new project, I prefer to keep my stack with only one language. So I love use javascript for everything, with Node.js, Express.js, React.js and I really like to use NoSQL databases like MongoDB in this case.

So I decided to share my experience of setting up this environment from scratch.

First, let's create a folder and generate our package.json file for this project.

```
$ mkdir node-react-starter
$ cd node-react-starter
$ npm init -y
```

Now, let's install the project dependencies


```
$ npm install --save express body-parser mongoose
```

> In this project we use [Express.js](https://expressjs.com), a very popular framework for Node.js applications.
> [body-parser](https://www.npmjs.com/package/body-parser) is used to parse incoming request bodies in a middleware before your handlers, available under the req.body property.
> [Mongoose](https://www.npmjs.com/package/mongoose) is a MongoDB object modeling tool designed to work in an asynchronous environment.


Then, install the development dependencies


```
$ npm install --save-dev nodemon concurrently
```

> [nodemon](https://www.npmjs.com/package/nodemon) is a package that runs the node.js application and listen to any file change, updating the entire app.

> [Concurrently](https://www.npmjs.com/package/concurrently) allows us to run multiple npm commands at the same time.

After installing the dependencies, you should get a file like this:

![package.json file example](https://thepracticaldev.s3.amazonaws.com/i/pvofb1ei1nn1rx5dirhf.png)

Let's create the project structure

```
$ mkdir models routes
$ touch index.js
```

Open the index.js file and add the following code:

```javascript
//  index.js

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

const app = express();

mongoose.Promise = global.Promise;
mongoose.connect(process.env.MONGODB_URI || `mongodb://localhost:27017/node-react-starter`);

app.use(bodyParser.json());

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log(`app running on port ${PORT}`)
});
```

After this, you can add a run script inside your package.json file, under scripts:
```json
"server": "nodemon index.js"
```

At this point, you can run your backend and have a successful connection with the mongodb (MongoDB must be up and running). You can run the script you just created like so:

```
$ npm run server
```

Let's initiate our version control to keep track of every change. But first we need to add a .gitignore file in the root of our project with the following content:

```
node_modules
.idea
```
Then, we initiate our version control

```
$ git init
$ git add .
$ git commit -am "first commit"
```

We successfully created our backend structure, now let's jump to the frontend.

Now, let's create a React app with [create-react-app](https://github.com/facebook/create-react-app).

```
$ create-react-app client
```

Now, in the client directory we have to add our dependencies.
Here we are going to use [yarn](https://www.npmjs.com/package/yarn) to add this dependencies.

```
$ cd client
$ yarn add axios
```

> [axios](https://www.npmjs.com/package/axios) is a very popular promise based HTTP client for the browser and node.js.

##For react-scripts >= 0.2.3

For the current react version (and any other react-scripts > 0.2.3), you can simply add the following line to your package.json file <strong>in the client directory</strong> and that will allow you to proxy your front-end requests to the back-end app.

```json
"proxy": "http://localhost:5000"
```

##For react-scripts < 0.2.3

If you are using an older version of react-scripts you might need to add the following configuration to be able to connect the front-end with the back-end:

```
$ cd client
$ yarn add http-proxy-middleware
```

> [http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware) is used to create a proxy from our react app to the backend app while on development.

We can now add the config file to setup the proxy to make requests from our frontend to our backend application. 
<strong>Remember to add this configuration only if you are using an older react version, being react-scripts < 0.2.3.</strong>

In the directory /client/src, add the file setupProxy.js with the following content

```javascript
// /client/src/setupProxy.js

const proxy = require('http-proxy-middleware')

module.exports = function(app) {
    app.use(proxy('/api/*', { target: 'http://localhost:5000' }))
}

```

In the package.json in the root of the project, let's add the following run scripts:

```
"client": "npm run start --prefix client",
"server": "nodemon index.js",
"dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"",
"start": "node index.js"
```

Now your package.json file should look like this:

```json
{
  "name": "node-react-starter",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "client": "npm run start --prefix client",
    "server": "nodemon index.js",
    "dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"",
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "mongoose": "^5.6.3"
  },
  "devDependencies": {
    "concurrently": "^4.1.1",
    "nodemon": "^1.19.1"
  }
}

```

Now you are able to run the project with the following command:

```
$ npm run dev
```

This will run the backend application on port 5000, and the frontend on port 3000.
You should see the react application running on http://localhost:3000

To make our project production ready, we need to add the following lines in our index.js file, right after the app.use(bodyParser.json()) call:

```javascript
if (process.env.NODE_ENV === 'production') {
  app.use(express.static('client/build'));

  const path = require('path');
  app.get('*', (req,res) => {
      res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
  })

}
```
This will redirect all the requests to our frontend application, unless we specify any route before this code.


Now let's create a simple interaction to see the proxy connection in action

Add the file Product.js inside the directory /models and insert the following code:

```javascript
// /models/Product.js

const mongoose = require('mongoose');
const {Schema} = mongoose;

const productSchema = new Schema({
    name: String,
    description: String,
})

mongoose.model('products', productSchema);
```

Let's create a route for our backend API.

Add the file productRoutes.js inside the directory /routes and insert the following code:

```javascript
// /routes/productRoutes.js
const mongoose = require('mongoose');
const Product = mongoose.model('products');

module.exports = (app) => {

  app.get(`/api/product`, async (req, res) => {
    let products = await Product.find();
    return res.status(200).send(products);
  });

  app.post(`/api/product`, async (req, res) => {
    let product = await Product.create(req.body);
    return res.status(201).send({
      error: false,
      product
    })
  })

  app.put(`/api/product/:id`, async (req, res) => {
    const {id} = req.params;

    let product = await Product.findByIdAndUpdate(id, req.body);

    return res.status(202).send({
      error: false,
      product
    })

  });

  app.delete(`/api/product/:id`, async (req, res) => {
    const {id} = req.params;

    let product = await Product.findByIdAndDelete(id);

    return res.status(202).send({
      error: false,
      product
    })

  })
  
}
```

We can now import the models and routes files inside our index.js like so:

```javascript
// /index.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');

// IMPORT MODELS
require('./models/Product');

const app = express();

mongoose.Promise = global.Promise;
mongoose.connect(process.env.MONGODB_URI || `mongodb://localhost:27017/node-react-starter`);

app.use(bodyParser.json());

//IMPORT ROUTES
require('./routes/productRoutes')(app);

if (process.env.NODE_ENV === 'production') {
  app.use(express.static('client/build'));

  const path = require('path');
  app.get('*', (req,res) => {
      res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
  })

}

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log(`app running on port ${PORT}`)
});
```

Now if we run the project we are able to make requests to our simple product api using the url http://localhost:5000/api/product.
Here we can get, insert, update and delete a product.


Back to the react application, lets add a service to make requests to the backend application. 
Inside the folder /client/src create a folder called services and add a file productService.js with the following content:

```javascript
//  /client/src/services/productService.js

import axios from 'axios';

export default {
  getAll: async () => {
    let res = await axios.get(`/api/product`);
    return res.data || [];
  }
}
```

Now let's edit the App.js file, adding a simple UI that shows a list of products:

```javascript
// /client/src/App.js

import React, { useState, useEffect } from "react";

// SERVICES
import productService from './services/productService';

function App() {
  const [products, setproducts] = useState(null);

  useEffect(() => {
    if(!products) {
      getProducts();
    }
  })

  const getProducts = async () => {
    let res = await productService.getAll();
    console.log(res);
    setproducts(res);
  }

  const renderProduct = product => {
    return (
      <li key={product._id} className="list__item product">
        <h3 className="product__name">{product.name}</h3>
        <p className="product__description">{product.description}</p>
      </li>
    );
  };

  return (
    <div className="App">
      <ul className="list">
        {(products && products.length > 0) ? (
          products.map(product => renderProduct(product))
        ) : (
          <p>No products found</p>
        )}
      </ul>
    </div>
  );
}

export default App;

```

At this point, you can run the application again using the command npm run dev, and you will see the following screen:

![](https://thepracticaldev.s3.amazonaws.com/i/xfa4yz3gbmlg4r9s3qh9.png)


Use a HTTP client like [Postman](https://www.getpostman.com/) or [Insomnia](https://insomnia.rest/) to add some products. Make a POST request to http://localhost:5000/api/product with the following JSON content:

```json
{
  "name": "<product name>",
  "description": "<product description here>"
}
```

Now, you will be able to see a list of products rendered on the screen, like so:

![](https://thepracticaldev.s3.amazonaws.com/i/8n282icdca6e01esu7eb.png)


I hope you may find this tutorial useful and in the following days I will continue this tutorial showing how to Dockerize this app. 

Also check this next post explaining [how to deploy this app to heroku](https://dev.to/thisk8brd/how-to-deploy-a-webapp-to-heroku-node-js-react-js-and-mongodb-5a7g).

If you are interested in working with containers, I also made this post that explains [How to dockerize this app and deploy to Heroku](https://dev.to/pacheco/how-to-dockerize-a-node-app-and-deploy-to-heroku-3cch).

The source code can be found [here](https://github.com/thisk8brd/node-react-starter)