Tutorials > How to create a Web App with Node.js and React on Ubuntu 20.04

How to create a Web App with Node.js and React on Ubuntu 20.04

Published on: 13 November 2020

Development Node.js React Ubuntu

Node.js is an open source Javascript platform used for running server-side Javascript code. In the following tutorial you will learn how to use it to create a simple Web App with Node.js and how to publish it online on your Linux Ubuntu 18.04 server.

You will also see how to use the React framework to create a web interface that uses our Web App. "Express" will be used as a framework to manage web requests, and SQLite for saving information.

The sample application will respond to REST calls, allowing the client to save and read a book archive.

To get started, connect to your server via an SSH connection. If you haven't done so yet, following our guide is recommended to  connect securely with the SSH protocol. In case of a local server go to the next step and open the terminal of your server .

Installing Node.js

Install Node.js via apt making sure to download the latest version available. To do so, first update your repositories, as follows:

$ sudo apt update && apt install nodejs
  

Before proceeding, update node to the latest stable version by running the following commands:

$ sudo npm cache clean -f 
$ sudo npm install -g n 
$ sudo n stable
  

Then, verify the correct installation of Node.js using the command:

$ nodejs -v
  

If successfully installed, then the installed version will be displayed on the screen.

Now let's move on to the installation of npm or the ‘Node Package Manager’, necessary to install additional modules for Node.js

$ sudo apt install npm
  

Creating the server application

To create an application compatible with the standards provided by Node.js, first initialize a basic configuration of npm.

Then, create a folder for the project, here, called "books", and move into it.

cd /var/
  sudo mkdir books
  cd books
  

Run the following console command in the newly created folder:

npm init

A wizard will start to create a package.json file with all the basic information about the project and its dependencies.

Use the suggested values ​​to move forward, as shown below:

This utility will walk you through creating a package.json file.
  It only covers the most common items, and tries to guess sensible defaults.
  
  See `npm help json` for definitive documentation on these fields
  and exactly what they do.
  
  Then, use `npm install ` to install a package and
  save it as a dependency in the package.json file.
  
  Press ^C at any time to quit.
  package name: (books)
  version: (1.0.0)
  description:
  entry point: (index.js)
  test command:
  git repository:
  keywords:
  author:
  license: (ISC)
  About to write to package.json:
  
  {
    "name": "books",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC"
  }
  
  Is this OK? (yes) yes
  

Answer ‘yes’ to complete the procedure.

Then, proceed by installing the two main modules:

$ npm install --save express sqlite3
  
  • express: a framework capable of handling incoming HTTP requests;
  • sqlite3: a client module that allows you to manage small databases, where to save your books.

By adding the --save parameter, npm is told to update package.json, adding these two dependencies to the project.

Then it is possible to proceed with the creation of the entry point for your application by originating the index.js file in the same directory as package.json.

Use your favorite text editor to paste the following content into the newly created file:

/**
   * First, include the two previously installed modules 
   */
  var express = require('express');
  
  var sqlite3 = require('sqlite3').verbose();
  
  /**
   * At this point create a database in memory ( i.e. 
   * not saving it on disk ) where to save your
   * our data


   */
  var db = new sqlite3.Database(':memory:');
  
  /**
   * Then create a new table with only two fields: 
   * - title : Book title
   * - author : Full name of the author
   */
  db.run("CREATE TABLE books (title TEXT, author TEXT)");
  
  /**
   * Initialize a new express application
   */
  var app = express();
  
  /**
   * Use the main server root to
   * list all the books 
   */
  app.get('/', function (req, res) {
  
      db.all(`SELECT * FROM books` , (err,rows) => {
  
          /**
           * Send all the lines in the “book” table
           */
          res.send( rows );
      });
  
  });
  
  /**
   * Use this path to save, instead:
   * /save/ followed by title and author
   */
  app.get('/save/:title/:author', function (req, res) {
  
      /**
       * Prepare the INSERT instruction in our table 
       */
      var stmt = db.prepare("INSERT INTO books VALUES (?, ?)");
  
      /**
       * And run the query above, moving the data in the url
       * nell url 
       */
      stmt.run( req.params.title, req.params.author , (err,rows) =>{
  
          /**
           * Finally, send a ‘true’  status to show that 
           * saving has been successful
           */
          res.send(true);
      });
  
      stmt.finalize();
  
  });
  
  /**
   * Therefore , run the listen server on port 80 
   */
  
  app.listen( 80, function () {
      console.log('Books server ready');
  });
  

Complete it by installing the project dependencies, starting the command:

$ sudo npm install
  

Starting the service

To start the Web App in a persistent way, use forever: a software capable of running and keeping scripts alive, even in the event of a server shutdown.

Install it using npm:

$ sudo npm install -g forever
  

Then, start your Web App:

$ forever start index.js
  

If everything works correctly, by visiting your virtual machine at its IP address, it will respond with:

[]
  

Then, use your browser to save the first 3 books by visiting the following URLs:

http://SERVER_IP/save/Il%20Decamerone/Giovanni%20Boccaccio
  
  http://SERVER_IP/save/Il%20fu%20Mattia%20Pascal/Luigi%20Pirandello
  
  http://SERVER_IP/Il%20barone%20rampante/Italo%20Calvino
  

P.S. Don’t forget to always replace the IP address with that of your instance.

So, make sure the books have been saved by navigating to the server's main URL:

http://SERVER_IP/
  

The server should return the following content:

[{"title":"Il Decamerone","author":"Giovanni Boccaccio"},{"title":"Il fu Mattia Pascal","author":"Luigi Pirandello"},{"title":"Il barone rampante","author":"Italo Calvino"}]
  

Creating Frontend with React

Then, proceed with the creation of the frontend of your React application to be able to interface with the newly created Web App, starting from its installation.

Make sure to be in the main "books" directory. Then, continue by typing the following commands:

$ npx create-react-app react-books
$ cd react-books
  

Once completed, the ‘react-books’ directory just created by the React tool will contain as follows :

/react-books 
        /node_modules 
        /public 
        /src

The most important directory is definitely "src" as it contains the source of your application. Replace the content of the file "App.js" present in "src" with the following listing listed below.

Start by importing all the necessary modules:

import React from 'react';
  import './App.css';
  import superagent from 'superagent';
  

Then, continue creating a class to manage the insertion of new books:

class InsertForm extends React.Component {
  
   constructor(props){
     super(props);
  
     // Set a basic status of the component 
     this.state = {
       title: '', // Titolo del libro Book title 
       author: '' // ed autore Author
     };
  
     this.onSubmit = this.onSubmit.bind(this);
   }
  
   // Function call to save the book
   onSubmit( se ){
     se.preventDefault();
  
     //Collect all the information inserted by the user
     const title = encodeURIComponent(this.state.title);
  
     const author = encodeURIComponent(this.state.author);
  
     // Reset all the  input fields 
     this.setState({
       title: '',
       author: ''
     });
  
     // Do the Ajax call to save the book 
     superagent.get( `http://SERVER_IP:8080/save/${title}/${author}` ).then( msg => {
  
       // Notify the container component of the saving
       this.props.onSave();
     });
  
   }
  
  render(){
     return <form onSubmit={this.onSubmit}>
  
       <div>
         <label>Title</label>
         <input type="title" value={this.state.title}
           onChange={se=>{this.setState({title: se.target.value})}}/>
       </div>
  
       <div>
         <label>Author</label>
         <input type="author" value={this.state.author}
           onChange={se=>{this.setState({author: se.target.value})}} />
       </div>
  
       <button onClick={this.onSubmit}>Salva</button>
      
     </form>;
   }
  
  } 
  

Then, define the main class to be called from the main file automatically created by create-react-app:

class App extends React.Component {
  
   constructor(props){
     super(props);
  
     //Set an empty list to start with
     this.state = {
       data: []
     };
  
     this.reloadData = this.reloadData.bind( this );
   }
  
   // Function to load again data from the server through Ajax 
   reloadData(){
     superagent.get( 'http://SERVER_IP:8080/' ).then( msg => {
  
       // Set the data read by the server as status 
       this.setState( {data: msg.body} );
     });
  
   }
  
   // Once the component is reloaded, load the data on the server
   componentDidMount(){
     this.reloadData();
   }
  
   render(){
     return <div style={{margin: '20px'}}>
  
       <div >
  
         <h2>Books list</h2>
  
         <ul> {/* Itero tutti i libri ricevuti dal server e genero dei <li /> */}
           {this.state.data.map( book => {
             return <li>{book.title} ({book.author})</li>
           })}
         </ul>
       </div>
  
       <h2>Save book</h2>
  
       {/* Insert the component defined above and, in case of saving update the book list  */} 
       <InsertForm onSave={this.reloadData} />
  
     </div>;
   }
  }
  

P.S. Make sure you change the IP address used in this tutorial with that of your server.

Finally, finish writing the file by exporting the "App" class:

export default App;
  

Once the export is completed, from the ‘react-books’ directory run the following command to compile your application:

$ npm run-script build
  

The command above will prepare a new "build" folder containing a compact version of the Javascript source ready to be used by a common web server or, as in this case, by the Express library used by the Web App.

Before concluding it, make a small change to the server, by modifying the listening port, previously indicated with:

app.listen( 80, function () {
      console.log('Books server ready');
  });
  

with a new port, the 8080:

app.listen( 8080, function () {
      console.log('Books server ready');
  });
  

Then, add the following piece of code to serve the static React files present in the "build" directory:

var reactApp = express();
  
  reactApp.use( '/' , express.static( 'react-books/build' ) );
  
  reactApp.listen( 80 , function() {
    console.log( 'React app ready' );
  } );
  

Finally, restart everything by running the command:

$ forever restartall
  

Running and testing the application

Proceed using a browser of your choice and visit the URL of your server, for example "http: // SERVER_IP /"

If everything works correctly, the following screen should be seen:
Book insertion test

Then, proceed by inserting a book:
Book insertion test

And press the "Save" button:
Book insertion test

Perfect! If everything works correctly, you have successfully created your first Web App with Node.js and Redis.

Consult the official React documentation to learn more about its use. Also, consider using a more powerful web server, such as NGINX, to serve React static files and API requests.