Skip to main content

Command Palette

Search for a command to run...

From Frontend to Backend: Building My First REST API πŸš€

Published
β€’7 min read
From Frontend to Backend: Building My First REST API πŸš€
E

Just a regular guy who wants to make an impact in the society

Introduction

As a frontend developer comfortable with React and Next.js, I recently joined the HNG internship backend track that pushed me out of my comfort zone. The first task? Build a RESTful API endpoint that integrates with an external API and returns dynamic data.

Spoiler alert: It was both challenging and enriching! Here's everything I learned building my first backend service from scratch.


πŸ“‹ The Challenge

The task was straightforward yet comprehensive:

Build a GET /me endpoint that:

  • Returns my profile information in JSON format

  • Fetches a random cat fact from an external API on every request

  • Includes a dynamic timestamp in ISO 8601 format

  • Handles errors gracefully with appropriate fallbacks

  • Implements rate limiting for security

  • Deploys to a production environment (no Vercel or Render allowed!)

Required Response Format:

{
  "status": "success",
  "user": {
    "email": "your.email@example.com",
    "name": "Your Full Name",
    "stack": "Node.js/Express"
  },
  "timestamp": "2025-10-19T14:30:45.123Z",
  "fact": "Cats can rotate their ears 180 degrees."
}

πŸ€” My Initial Thoughts

Coming from frontend development, I was familiar with consuming APIs but had never built one myself. Questions flooded my mind:

  • How do I structure a backend project?

  • What's the difference between middleware and route handlers?

  • How do I handle errors when external APIs fail?

  • What even is rate limiting, and how do I implement it?

Time to dive in! πŸ’ͺ


πŸ› οΈ Tech Stack Selection

I chose Node.js with Express because:

  1. JavaScript familiarity - I already knew JS from React

  2. Quick setup - Express is minimal and straightforward

  3. Rich ecosystem - Tons of packages available via npm

  4. Great learning curve - Perfect for backend beginners

Dependencies Used:

  • express - Web framework for routing and middleware

  • axios - HTTP client for external API calls

  • dotenv - Environment variable management

  • nodemon - Development server with auto-reload


πŸ—οΈ Building the API - Step by Step

Step 1: Project Setup

mkdir hng-stage-0-backend
cd hng-stage-0-backend
npm init -y
npm install express axios dotenv
npm install --save-dev nodemon

Simple enough! Coming from React, this felt similar to create-react-app, just more manual.

Step 2: Understanding Express Basics

This was my biggest "aha!" moment. In React, I write components. In Express, I write routes and middleware.

React Component (what I knew):

function Profile() {
  return <div>Profile Data</div>;
}

Express Route (what I learned):

app.get('/me', (req, res) => {
  res.json({ data: 'Profile Data' });
});

Both handle requests and return data - just different environments!

Step 3: Creating the Main Endpoint

Here's the core implementation:

app.get('/me', async (req, res) => {
  try {
    // Fetch cat fact from external API
    const catFact = await fetchCatFact();

    // Generate current timestamp
    const timestamp = new Date().toISOString();

    // Build response
    const response = {
      status: 'success',
      user: {
        email: 'your.email@example.com',
        name: 'Your Full Name',
        stack: 'Node.js/Express'
      },
      timestamp: timestamp,
      fact: catFact
    };

    res.status(200).json(response);
  } catch (error) {
    console.error('Error:', error);
    res.status(500).json({
      status: 'error',
      message: 'Internal server error'
    });
  }
});

Key Learning: Always wrap async operations in try-catch blocks for safety

Step 4: Integrating External API

This part felt familiar just like fetching data in React, but on the server side:

async function fetchCatFact() {
  try {
    const response = await axios.get('https://catfact.ninja/fact', {
      timeout: 5000,
      headers: { 'Accept': 'application/json' }
    });
    return response.data.fact;
  } catch (error) {
    console.error('Cat API failed:', error.message);
    // Fallback if external API is down
    return 'Cats sleep 70% of their lives. (Fallback - API unavailable)';
  }
}

Lesson Learned: Always have a fallback! External APIs can fail, and your app should handle it gracefully.

Step 5: Implementing Rate Limiting

This was completely new territory. Rate limiting prevents abuse by limiting how many requests a user can make.

const rateLimit = new Map();
const MAX_REQUESTS = 30; // per minute
const RATE_LIMIT_WINDOW = 60000; // 1 minute

const rateLimiter = (req, res, next) => {
  const ip = req.ip;
  const now = Date.now();

  if (!rateLimit.has(ip)) {
    rateLimit.set(ip, { count: 1, resetTime: now + RATE_LIMIT_WINDOW });
    return next();
  }

  const record = rateLimit.get(ip);

  if (now > record.resetTime) {
    record.count = 1;
    record.resetTime = now + RATE_LIMIT_WINDOW;
    return next();
  }

  if (record.count >= MAX_REQUESTS) {
    return res.status(429).json({
      status: 'error',
      message: 'Too many requests'
    });
  }

  record.count++;
  next();
};

// Apply to route
app.get('/me', rateLimiter, async (req, res) => { ... });

Mind Blown: Middleware is just a function that runs before your route handler! It's like a React Context or HOC, but for the backend.


🚒 Deployment Journey

The Challenge

No Vercel or Render allowed so I chose Railway for its simplicity and generous free tier.

Deployment Steps:

  1. Pushed to GitHub

  2. Connected Railway to my GitHub repo

  3. Set environment variables in Railway dashboard

  4. Generated public domain

  5. Tested the live endpoint πŸŽ‰

Live URL: hng-stage-0-backend-production-9495.up.railway.app

Deployment Gotcha

Initially, my app crashed because I hardcoded PORT=3000. Railway uses dynamic ports!

Fix:

const PORT = process.env.PORT || 3000;

Always respect environment variables in production! πŸ“


πŸ› Challenges I Faced

Challenge 1: Understanding Middleware

Problem: I didn't understand the order of middleware execution.

Solution: Middleware runs top-to-bottom! Think of it as a pipeline:

Request β†’ CORS β†’ Logging β†’ Rate Limiter β†’ Route Handler β†’ Response

Challenge 2: Handling External API Failures

Problem: What if the Cat Facts API is down?

Solution: Always implement fallbacks with try-catch blocks and provide default data.

Challenge 3: CORS Errors

Problem: When testing from a frontend, I got CORS errors.

Solution: Added CORS headers:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});

Challenge 4: Git Tracking node_modules

Problem: Accidentally committed node_modules/ to GitHub.

Solution:

git rm -r --cached node_modules
git commit -m "Remove node_modules"

Lesson: Create .gitignore BEFORE your first commit!


πŸ’‘ Key Takeaways

1. Backend β‰  Hard, Just Different

The concepts aren't harder than frontend - they're just different. Once I mapped them to what I knew (routes = components, middleware = HOCs), everything clicked.

2. Error Handling is Critical

On the frontend, a failed fetch might just show an error message. On the backend, poor error handling can crash your entire server! Always use try-catch.

3. Environment Variables Are Your Friend

Never hardcode sensitive data or configuration. Use .env locally and set variables in your deployment platform.

4. Testing Matters

I tested my endpoint with:

  • curl commands

  • Browser

  • Postman

  • Multiple networks

Each revealed different issues!

5. Documentation is Gold

Writing a clear README helped me understand my own code better and made deployment smoother.


πŸ“Έ Screenshots & Results

Local Testing:

$ curl http://localhost:3000/me

{
  "status": "success",
  "user": {
    "email": "yourname@example.com",
    "name": "Your Name",
    "stack": "Node.js/Express"
  },
  "timestamp": "2025-10-19T14:30:45.789Z",
  "fact": "Cats have 32 muscles in each ear."
}

Production Testing:

$ curl hng-stage-0-backend-production-9495.up.railway.app

βœ… 200 OK
βœ… All fields present
βœ… Dynamic timestamp
βœ… Fresh cat fact on each request

Rate Limiting Test: After 30 requests in a minute:

{
  "status": "error",
  "message": "Too many requests. Please try again later."
}

🎯 What's Next?

This task opened my eyes to backend development! Next steps on my learning journey:

  1. Database Integration - Add MongoDB/PostgreSQL

  2. Authentication - JWT tokens and user sessions

  3. Advanced Error Handling - Custom error classes

  4. Testing - Write unit and integration tests with Jest

  5. WebSockets - Real-time features

  6. Microservices - Break into smaller services


πŸ“š Resources That Helped



πŸ’­ Final Thoughts

Going from frontend to backend felt like learning to cook after years of food delivery. Both get you fed, but understanding what happens "in the kitchen" gives you so much more control and appreciation for the full stack.

To any frontend devs hesitant about backend: Just start! You already know more than you think. JavaScript is JavaScript, whether it's running in the browser or on a server. The patterns are similar, just the environment is different.

This was Stage 0 of my backend journey, and I can't wait to see where it goes! πŸš€


πŸ‘‹ Let's Connect

Found this helpful? Have questions? Let's chat!

Drop your backend learning experiences in the comments below! πŸ‘‡


#Backend #NodeJS #API #WebDevelopment #LearningInPublic #BackendDevelopment #JavaScript #ExpressJS #100DaysOfCode