DEV Community

Cover image for Building a COVID19 Dashboard using Node.js
Julian Pufler
Julian Pufler

Posted on • Updated on

Building a COVID19 Dashboard using Node.js

Hey there! My name is Julian.

I am one of the core-maintainers of the NovelCOVID API, which is an open-source API for COVID19 related data.
In this article, I would like to show you how easy it is to build a COVID19 dashboard using our API.
A few weeks ago, I built Covid Detail, Covid Overview and Covid19 Daily Digest with the data provided by the API.

This guide is for people that know a bit about coding and are interested in the topics presented.
Complete beginners might have a hard time understanding some of the concepts portrayed in the article.
I advise experienced coders to check out the API Documentation and my API Wrapper.

Preparation

We are going to build a Node.js project using Express and EJS (a templating engine). You will need to have Node.js installed.

  • Create a new folder for your project, you can choose any name but I will call mine covid-dashboard.
  • Open the folder in your terminal and run npm init -y to generate a package.json file.
  • Create a file called app.js and two folders called public and views in the root of the project.
  • In public/, create a main.css file and in views/, create a index.ejs file.

Your project directory should now look like this:



  covid-dashboard
  ├── package.json
  ├── app.js
  ├── public
  │   └── main.css
  └── views
      └── index.ejs


Enter fullscreen mode Exit fullscreen mode

Step 1: Installing dependencies

Alright, so after preparing our project, we can start adding our dependencies. For this project, we are going to need 3 packages:

  • Express (web framework)
  • EJS (templating engine)
  • NovelCOVID (API wrapper)

Install them by running:
npm install --save express ejs novelcovid

Step 2: Setting up the server

After installing all the packages we will use, it's time to code!

  • First we need to require our packages express and novelcovid, then we can create our express object by calling express().
  • After that we set our view directory to the folder views/ and specify our view engine, in this case ejs. Then we tell express to expose the contents of public/ on the server root so we can use them in the frontend.
  • Now we can start our server by calling app.listen(...) and passing in our port of choice, in my case 8080, and a callback.

I have also specified a GET route in the example below. If you start your server now using node ./app.js and open localhost:8080/ in your browser, you will receive a greeting.
The server works!



// app.js
const express = require('express');
const api = require('novelcovid');

const app = express();

app.set('views', './views');
app.set('view engine', 'ejs');
app.use(express.static('./public'));

app.get('/*', (req, res) => res.send('Hello!'));

app.listen(8080, () => console.log('running on port 8080'));


Enter fullscreen mode Exit fullscreen mode

Step 3: Creating our views

In this step, we are going to use EJS to interpolate javascript variables into EJS templates to create HTML that can be sent to the client. It sounds way more complicated than it actually is, you will see in a bit.
In EJS you can use <%= variable %> to interpolate variables into your EJS template which will then be transformed into HTML.



<!-- index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
  <title>COVID19 Dashboard</title>
  <link rel="stylesheet" href="/main.css">
</head>
<body>
  <div class="container">
    <h1>COVID19 Dashboard</h1>
    <table>
      <thead>
        <tr>
          <th>Name</th> 
          <th>Cases</th> 
          <th>Active</th> 
          <th>Recovered</th> 
          <th>Deaths</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Global</td>
          <td><%= cases %></td>
          <td><%= active %></td>
          <td><%= recovered %></td>
          <td><%= deaths %></td>
        </tr>
      </tbody>
    </table>
  </div>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

Don't worry if you don't understand what this means yet, just keep on reading.

Step 4: Displaying data using EJS

The EJS example above shows a table with 1 row, the first column of the row being 'Global' and its other columns being interpolated variables.
That's all we need to do in EJS.

But where do these values come from and how do we pass them over to the template?

Let me break this up into 2 small steps, getting the data and passing it to the template.

  • Getting the data As mentioned at the beginning, we will use the novelcovid package to retrieve data from the API. We will use the function api.all() to fetch global data. Don't forget that the wrapper exposes asynchronous functions, so you have to make the request handler async.
  • Passing it to the template res.render(...) lets you specify a template view's name and optional variables to be interpolated and sends the HTML created from that template view and the variables passed to the client. ```js

// app.js
...
app.get('/*', async (req, res) => {
const global = await api.all();
res.render('index', { global });
});
...

If you start up your server again using `node ./app.js` and head over to `localhost:8080/` in your browser, you should see something like this:

![Dashboard with global data](https://user-images.githubusercontent.com/17516174/82122085-b622af80-9791-11ea-83ca-62b91f7f6601.png)

Amazin how easy that was, right? But it doesn't really look that good, yet. 
Let's add all countries to the list and then use CSS to style the table.

# Step 5: Country Data and Styling
The `novelcovid` package exposes a wide variety of functions to get data from the different endpoints we offer. One of them is `api.countries()`, which lets you retrieve a list of all countries and their data. **Exactly what we need!**

> But how can we make EJS create a table row for each country?

That's very easy. EJS lets you do loops and if clauses. I mean the name literally is 'Embedded JavaScript', just let that sink in. If you wanna know more, head over to their [website](https://ejs.co). 
```html


<!-- index.ejs -->
...
<tbody>
    <tr>
        <td>Global</td>
        <td><%= cases %></td>
        <td><%= active %></td>
        <td><%= recovered %></td>
        <td><%= deaths %></td>
    </tr>
    <% for (const country of countries) { %>
        <tr>
            <td><%= country.country %></td>
            <td><%= country.cases %></td>
            <td><%= country.active %></td>
            <td><%= country.recovered %></td>
            <td><%= country.deaths %></td>
        </tr>
    <% } %>
</tbody>
...


Enter fullscreen mode Exit fullscreen mode

After updating our template, we now need to pass a variable called countries over to our EJS template in our request handler, so let's do that.



// app.js
...
app.get('/*', async (req, res) => {
  const global = await api.all();
  const countries = await api.countries({ sort: 'cases' });
  res.render('index', { global, countries });
});
...


Enter fullscreen mode Exit fullscreen mode

Spin up the server again and you should now see a big list of countries. Still ugly.
Let's add some styling. You can find my example main.css below but you can style it however you like!

The .container class is our wrapper for the table, I will make it a maximum width of 700 pixels and center it. The stylings for tr, th and td elements is for the table.



# main.css
body {
box-sizing: border-box;
margin: 0;
font-family: 'Lucida Sans', Geneva, Verdana, sans-serif;
}

.container {
width: 700px;
text-align: center;
margin: 0 auto;
padding: 25px 0 0 0;
}

tr {
text-align: left;
}

tbody > tr:not(:nth-child(2n)) {
background-color: #eee;
}

th {
font-size: 125%;
padding-bottom: 10px;
}

td {
padding: 5px;
}

td:not(:first-child) {
text-align: right;
}

Enter fullscreen mode Exit fullscreen mode




The dashboard is finished! Look how easy that was!

COVID-Dashboard

You can find all the code on Github.

I really hope you liked the article, if not, please send me feedback to my email. If you have any questions regarding the NovelCOVID API, join our Discord Server.

Happy coding! - Julian

Top comments (0)