---
title: "Visualizing Economic Indicators - A Full-Stack Application with Node.js, React, Express.js, and Next.js"
description: "we'll create a dynamic web application that visualizes two key economic indicators: inflation rates and the Bank of Canada's overnight rates, over a selectable time period. Our application will leverage the Bank of Canada's API for real-time data fetching and display the information using a line graph. We'll employ a Node.js backend to retrieve the data and a React NextJS frontend for rendering the chart"
author: "Nariman Mani"
date: "February 10, 2024"
canonical: "https://manistechmind.com/posts/express-nextjs"
---

> Machine-readable edition. The canonical article is https://manistechmind.com/posts/express-nextjs.

# Visualizing Economic Indicators - A Full-Stack Application with Node.js, React, Express.js, and Next.js

![](/img/express-nextjs-bocrates.png)


## Backend Development with Express
### Step 1: Initialize Your Node.js Project
Create a new directory for your project and initialize a Node.js application:

```bash
mkdir economic-indicators
cd economic-indicators
npm init -y
```

Step 2: Install Dependencies
We need Express for our server framework and Axios for HTTP requests:

```bash
npm install express axios
```

Step 3: Create the Express Server
In your project directory, create a file named server.js. This server will have two routes: one for inflation data and another for overnight rates.


Inflation Data Route:

```js

const express = require('express');
const axios = require('axios');
const app = express();
const port = 3001; // Different from Next.js port

app.get('/api/inflation', async (req, res) => {
    const months = req.query.months || '120';
    const url = `https://www.bankofcanada.ca/valet/observations/group/CPI_MONTHLY/json?recent=${months}`;
    try {
        const response = await axios.get(url);
        const data = response.data;
        res.json({
            dates: data.observations.map(obs => obs.d),
            rates: data.observations.map(obs => obs.CPIW ? obs.CPIW.v : null)
        });
    } catch (error) {
        console.error(error);
        res.status(500).send('Error fetching inflation data');
    }
});
```

Overnight Rates Route:

```js
app.get('/api/overnight-rates', async (req, res) => {
    const months = req.query.months || '120';
    const apiURL = `https://www.bankofcanada.ca/valet/observations/V122514/json?recent=${months}`;
    try {
        const response = await axios.get(apiURL);
        const data = response.data;
        res.json({
            dates: data.observations.map(obs => obs.d),
            rates: data.observations.map(obs => obs.V122514.v)
        });
    } catch (error) {
        console.error('Error fetching overnight rates:', error);
        res.status(500).send('Error fetching overnight rates');
    }
});

app.listen(port, () => {
    console.log(`Server running on http://localhost:${port}`);
});
```

Step 4: Run Your Server
Start your server with:

```bash
node server.js
```

### Frontend Development with React and Next.js
Step 1: Create Your Next.js App
In a new directory, initialize your Next.js app:

```bash
npx create-next-app@latest frontend
cd frontend
```

Step 2: Install Frontend Dependencies
Install Axios for making HTTP requests, react-chartjs-2 for charting, and chart.js:

```bash
npm install axios react-chartjs-2 chart.js
```

Step 3: Implement the Chart Component
Create a new file InflationChart.js in the components directory of your Next.js app. Use the provided React component code to implement the chart logic, which fetches data from your backend and displays it using react-chartjs-2.
Below code also includes the implementation of a function to export the chart as a PDF document.
```js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Line } from 'react-chartjs-2';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';

import {
    Chart as ChartJS,
    CategoryScale,
    LinearScale,
    PointElement,
    LineElement,
    Title,
    Tooltip,
    Legend,
  } from 'chart.js';
  
  ChartJS.register(
    CategoryScale,
    LinearScale,
    PointElement,
    LineElement,
    Title,
    Tooltip,
    Legend
  );

  const InflationChart = () => {
    const [chartData, setChartData] = useState({ labels: [], datasets: [] });
    const [selectedMonths, setSelectedMonths] = useState(120);


    const fetchData = (months) => {
        const fetchInflationData = axios.get(`http://localhost:3002/api/inflation?months=${months}`);
        const fetchOvernightRates = axios.get(`http://localhost:3002/api/overnight-rates?months=${months}`);

        Promise.all([fetchInflationData, fetchOvernightRates])
        .then(responses => {
            const inflationData = responses[0].data;
            const overnightRatesData = responses[1].data;

         // Combine the data
         const combinedData = inflationData.dates.map((date, index) => ({
            date: date,
            inflationRate: parseFloat(inflationData.rates[index]),
            overnightRate: parseFloat(overnightRatesData.rates[index])
        }));

        // Sort the combined data by date
        combinedData.sort((a, b) => new Date(a.date) - new Date(b.date));


        setChartData({
            labels: combinedData.map(item => item.date),
            datasets: [
                {
                    label: 'Inflation Rate',
                    data: combinedData.map(item => item.inflationRate),
                    borderColor: 'rgba(75, 192, 192, 1)',
                    backgroundColor: 'rgba(75, 192, 192, 0.5)',
                    yAxisID: 'y1',
                },
                {
                    label: 'Overnight Rate',
                    data: combinedData.map(item => item.overnightRate),
                    borderColor: 'rgba(255, 99, 132, 1)',
                    backgroundColor: 'rgba(255, 99, 132, 0.5)',
                    yAxisID: 'y2',
                }
            ]
        });
    })
            .catch(error => console.error('Error fetching data:', error));
    };


    useEffect(() => {
        fetchData(selectedMonths);
    }, [selectedMonths]);
    const handleMonthSelectionChange = (event) => {
        setSelectedMonths(event.target.value);
    };


    const exportChartToPDF = () => {
        const input = document.getElementById('chart-container'); // The element containing the chart
        html2canvas(input, { scale: 5 })
            .then((canvas) => {
                const imgData = canvas.toDataURL('image/png');
                const pdf = new jsPDF();

                   // Get PDF page dimensions
                   const pdfWidth = pdf.internal.pageSize.getWidth();
                   const pdfHeight = pdf.internal.pageSize.getHeight();
   
                   // Calculate scaled dimensions to maintain aspect ratio
                   const canvasAspectRatio = canvas.width / canvas.height;
                   let imgWidth = pdfWidth * 3/4;
                   let imgHeight = imgWidth / canvasAspectRatio;
   
                   // Check if height exceeds page height, adjust accordingly
                   if (imgHeight > pdfHeight) {
                       imgHeight = pdfHeight;
                       imgWidth = imgHeight * canvasAspectRatio;
                   }
   
                   // Calculate positions to center the image
                   const x = (pdfWidth - imgWidth) / 2;
                   const y = (pdfHeight - imgHeight) /5;

                pdf.addImage(imgData, 'PNG', x, y, imgWidth, imgHeight,'','FAST');
                pdf.save("chart.pdf");
            })
            .catch(err => {
                console.error('Error exporting chart:', err);
            });
    };

    return (
        <div>
        <div >
       
        <div id="chart-container" >
        <h1 className="users-heading">Inflation and Overnight Rate Over Time</h1>
        <Line
            data={chartData}
            options={{
                scales: {
                    y1: {
                        type: 'linear',
                        display: true,
                        position: 'left',
                    },
                    y2: {
                        type: 'linear',
                        display: true,
                        position: 'right',
                        grid: {
                            drawOnChartArea: false,
                        },
                    },
                },
            }}
        />
        </div>
        <div>
            {[12, 24, 36, 48, 60, 72, 84, 96, 108, 120].map(month => (
                <label key={month}>
                    <input
                        type="radio"
                        value={month}
                        checked={selectedMonths === month.toString()}
                        onChange={handleMonthSelectionChange}
                    />
                    {month} Months
                </label>
            ))}
        </div>
    </div>
    <button onClick={exportChartToPDF}>Export as PDF</button>
  
    </div>
    
    );
};

export default InflationChart;

```




Step 4: Display the Chart
Edit the pages/index.js file to import and display your InflationChart component.

```js
import React from 'react';
import '../styles/UserStyles.css'; // Import the CSS
import InflationChart from '../components/InflationChartC'; // Adjust the import path as needed

const Inflation = () => {
    return (
        <div className="users-container">
      
            <InflationChart />
        </div>
    );
};

export default Inflation;
```

Step 5: Run Your Next.js App
Start your Next.js application:

```bash
npm run dev
```

Your application will now be accessible at http://localhost:3000, and it should display the inflation and overnight rates chart using data fetched from your Express backend.

### Conclusion
Congratulations! You've built a full-stack web application that visualizes real-time economic data from the Bank of Canada. This project showcased how to set up a simple Express backend to fetch and serve API data, and a React frontend with Next.js to display this data in a dynamic chart. This tutorial provides a foundation for building more complex full-stack applications using these technologies.
