DEV Community

Bruno
Bruno

Posted on

Full Stack setup from scratch - Node.js, Express.js, React.js and Lowdb (Part 1)

  1. Setup
  2. Filter pages to print
  3. Deploy to Heroku

First, in command line, let's create a project folder and a package.json file:

mkdir node-react-project
cd node-react-project
npm init -y

package.json

  • name defines the name of the application or package;
  • version indicates the current version;
  • description is a summary of your application/package;
  • main defines the application entry point;
  • private (true) prevents your application from being accidentally published to npm;
  • scripts defines a set of Node scripts for you to execute;
  • dependencies defines a list of installed npm packages as dependencies;
  • devDependencies defines a list of installed npm packages as development dependencies;
  • engines defines which Node versions this package /application works;
  • browserslist is used to tell which browsers (and versions) you want to support;

Now, let's install the project dependencies:

npm install --save express body-parser lowdb

Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
body-parser Node.js body parsing middleware. Parse incoming request bodies in a middleware before your handlers, available under the req.body property.
lowdb is a small JSON database for Node, Electron and the browser.

Install the development dependencies:

npm install --save-dev nodemon concurrently

nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.
concurrently run multiple commands concurrently.

Then, we have package.json like this:

Let's create the project scructure:

mkdir routes
touch index.js

In the index.js we will add the following code:

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

const app = express();

app.use(bodyParser.json());

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

So, add the "server" entry into the "scripts" section of your package.json:

"server": "nodemon index.js"

Then, we can execute that script to run backend:

npm run server

Before starting version control, let's create a .gitignore file in the project's root folder and add the following line:

node_modules

After that, create a new repository on GitHub and upload our source code to that.

git init
git add .
git commit -m "backend configuration"
git remote add origin https://github.com/brunobc/node-react-project.git
git push -u origin master

Now, let's create a frontend with create-react-app and add dependencies:

npx create-react-app front
cd front
npm install --save http-proxy-middleware axios

http-proxy-middleware is a node.js proxying from frontend to backend.
axios is a promise based HTTP client for the browser and node.js.

In client directory /front/src, let's add the file setupProxy.js to proxy from frontend to backend.

const { createProxyMiddleware } = require('http-proxy-middleware')

module.exports = function(app) {
  app.use('/api/', createProxyMiddleware({
    target: 'http://localhost:5000',
    changeOrigin: true
  }));
}

In the package.json, in the root project, add the scripts:

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

To run the project in production, we need to add the following code after app.use(bodyParser.json()), in your index.js file. That will redirect all requests from the frontend.

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

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

Let's create the database file, as required by LowDB, naming it as db.json in the root project, then let's use shortid to create the user' ids.

touch db.json
npm install --save shortid

In db.json:

{
  "users": []
}

Now let's create the routes for our backend API.
We added the userRoutes.js file to the /routes directory. Then, add the following snippet:

const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
const shortid = require('shortid');

const adapter = new FileSync('db.json');
const db = low(adapter);

module.exports = (app) => {

  app.get(`/api/users`, async (req, res) => {
    const users = db.get('users').value();
    return res.status(200).send(users);
  });

  app.post(`/api/user`, async (req, res) => {
    const { name, lastName } = req.body;
    const id = shortid.generate();
    const users = db
      .get('users')
      .push({ id, name, lastName })
      .write();

    const user = db.get('users')
      .find({ id })
      .value();

    return res.status(201).send({
      error: false,
      user
    });
  })

  app.put(`/api/user`, async (req, res) => {
    const { name, lastName, id } = req.body;

    let users = db.get('users')
        .find({ id })
        .assign({ name, lastName })
        .write();

    const user = db.get('users')
      .find({ id })
      .value();

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

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

    db.get('users')
      .remove({ id })
      .write()

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

  })

}

Finally, open the index,js file, and after app.use(bodyParser.json()), configure the api routes:

require('./routes/userRoutes')(app);

Now we can run the backend using the url:http://localhost:5000/api/users and do get, insert, update e delete a user.

We can use Postman to add new users. Make a POST to http://localhost:5000/api/user with the json using this payload:

{
  "name": "Bruno",
  "lastName": "Bezerra"
}

To facilitate the use of requests, just import the following collecion in postman.

Now on the frontend (react) we will add a service in the /front/src/services folder called user.service.js to make requests.

import axios from 'axios';

export default {
  getAll: async () => {
    let res = await axios.get(`/api/users`);
    return res.data || [];
  },
  add: async (name, lastName) => {
    let res = await axios.post(`/api/user/`, { name, lastName })
    return res.data || {};
  },
  edit: async (name, lastName, id) => {
    let res = await axios.put(`/api/user/`, { name, lastName, id })
    return res.data || {};
  },
  delete: async (id) => {
    let res = await axios.delete(`/api/user/${id}`);
    return res.data || [];   
  }
}

Edit the App.js to list users:

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

import userService from './services/user.service';

function App() {
  const [ users, setUsers ] = useState(null);

  useEffect(() => {
    if (!users) {
      getUsers();
    }
  })

  const getUsers = async () => {
    let res = await userService.getAll();
    setUsers(res);
  }

  const renderUser = user => {
    return (
      <li key={user._id} className="list__item user">
        <h3 className="user__name">{user.name}</h3>
        <h3 className="user__lastName">{user.lastName}</h3>
      </li>
    );
  };

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

export default App;

And finally, we can run the command at the root of the project to run the backend and frontend:

npm run dev

I hope this application is useful and serves as a starting point for future projects. :)
The source code can be found in node-react-project.

Top comments (0)