Building and Deploying a Number Classification API with JavaScript | DevOps 1

ยท

4 min read

Introduction

In this blog post, I'll walk you through my journey of building and deploying a Number Classification API using JavaScript. This project was part of the HNG DevOps Stage 1 task, designed to enhance my understanding of APIs, server-side development, and cloud deployment.

The API classifies numbers based on interesting mathematical properties like primality, Armstrong status, digit sum, and parity (odd/even). Additionally, it fetches a fun fact about the number from the Numbers API.


Project Setup

1. Initializing the Project

I started by setting up a Node.js environment:

mkdir number-classification-api
cd number-classification-api
npm init -y

Then, I installed the necessary packages:

npm install express cors axios
  • Express: For handling API requests.

  • CORS: To enable cross-origin resource sharing.

  • Axios: For making HTTP requests to the Numbers API.

2. Developing the API

I created an index.js file:

const express = require('express');
const cors = require('cors');
const axios = require('axios');

const app = express();
app.use(cors());

app.get('/api/classify-number', async (req, res) => {
    const number = req.query.number;

    if (isNaN(number)) {
        return res.status(400).json({ number, error: true });
    }

    const num = parseInt(number);
    const isPrime = (n) => {
        if (n < 2) return false;
        for (let i = 2; i <= Math.sqrt(n); i++) {
            if (n % i === 0) return false;
        }
        return true;
    };

    const isArmstrong = (n) => {
        const digits = n.toString().split('').map(Number);
        return digits.reduce((acc, digit) => acc + Math.pow(digit, digits.length), 0) === n;
    };

    const digitSum = num.toString().split('').reduce((acc, digit) => acc + Number(digit), 0);

    let properties = [];
    if (isArmstrong(num)) properties.push('armstrong');
    properties.push(num % 2 === 0 ? 'even' : 'odd');

    try {
        const funFact = await axios.get(`http://numbersapi.com/${num}/math?json`);

        res.json({
            number: num,
            is_prime: isPrime(num),
            is_perfect: false, // Placeholder
            properties,
            digit_sum: digitSum,
            fun_fact: funFact.data.text
        });
    } catch (error) {
        res.status(500).json({ error: 'Error fetching fun fact' });
    }
});

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

3. Testing Locally

I tested the API using Postman and my browser:

node index.js

Then visited: http://localhost:3000/api/classify-number?number=371


Deployment on DigitalOcean

1. Setting Up the Server

I used DigitalOcean to deploy the API:

  • Droplet Creation: Created an Ubuntu droplet.

  • SSH Access:

      ssh root@<your-server-ip>
    
  • Updating the System:

      sudo apt update && sudo apt upgrade -y
    

2. Installing Node.js and Git

sudo apt install nodejs npm git -y

3. Cloning the Repository

cd /var/www
sudo git clone https://github.com/your-username/number-classification-api.git
cd number-classification-api
npm install

4. Running the API

node index.js

To keep it running in the background:

npm install -g pm2
pm2 start index.js

5. Setting Up NGINX (Reverse Proxy)

sudo apt install nginx -y
sudo nano /etc/nginx/sites-available/number-api

NGINX Config:

server {
    listen 80;
    server_name <your-server-ip>;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Enable and restart NGINX:

sudo ln -s /etc/nginx/sites-available/number-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Now, the API is accessible at http://<your-server-ip>/api/classify-number?number=371


Challenges Faced

  1. CORS Errors: Initially, I forgot to enable CORS, which caused errors when accessing the API from different origins. Adding app.use(cors()) fixed this.

  2. Server Downtime: The Node server stopped after SSH sessions ended. I resolved this using PM2.

  3. NGINX Configuration: Misconfigured reverse proxy settings caused 502 errors. Double-checking NGINX logs helped me debug (sudo tail -f /var/log/nginx/error.log).


Key Learnings

  • Improved my API development skills with Express.

  • Understood the importance of input validation and error handling.

  • Gained practical experience with deploying applications on DigitalOcean and configuring NGINX.


References


Conclusion

This project was an exciting dive into the world of APIs and cloud deployment. I enjoyed the hands-on experience of building something functional and deploying it for real-world access. If you're new to DevOps, I highly recommend trying out similar projects to solidify your learning.

You can check out the live API here and explore the GitHub repository.

Happy coding! ๐Ÿš€

ย