Episode 16 of 17

Creating a Front-end

Build a simple front-end that consumes your REST API — fetch and display data from the API in the browser.

Creating a Front-end

Your REST API is complete — it handles GET, POST, PUT, and DELETE requests with MongoDB. Now it is time to build a front-end that consumes the API and displays the data in the browser.

Setting Up

We will create a simple HTML page that uses the Fetch API to communicate with the REST API. No front-end framework is needed for this — just plain HTML, CSS, and JavaScript.

Serving Static Files

// index.js — add static file serving
app.use(express.static('public'));

Create a public/ folder in your project root. Express will serve any files in this folder. Navigating to http://localhost:3000 will load public/index.html.

The HTML Page

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ninja API</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1>Ninja Directory</h1>

        <form id="ninja-form">
            <input type="text" id="name" placeholder="Ninja name" required>
            <input type="number" id="rank" placeholder="Rank (1-10)" min="1" max="10" required>
            <button type="submit">Add Ninja</button>
        </form>

        <div id="ninja-list"></div>
    </div>
    <script src="app.js"></script>
</body>
</html>

Fetching Data from the API

// public/app.js

// GET all ninjas and display them
async function loadNinjas() {
    const response = await fetch('/api/ninjas');
    const ninjas = await response.json();

    const list = document.getElementById('ninja-list');
    list.innerHTML = ninjas.map(ninja => `
        <div class="ninja-card">
            <h3>${ninja.name}</h3>
            <p>Rank: ${ninja.rank}</p>
            <button onclick="deleteNinja('${ninja._id}')">Delete</button>
        </div>
    `).join('');
}

// Load ninjas on page load
loadNinjas();

The Fetch API

MethodFetch Call
GETfetch('/api/ninjas')
POSTfetch('/api/ninjas', { method: 'POST', headers, body })
PUTfetch('/api/ninjas/id', { method: 'PUT', headers, body })
DELETEfetch('/api/ninjas/id', { method: 'DELETE' })

Posting Data (Creating a Ninja)

document.getElementById('ninja-form').addEventListener('submit', async (e) => {
    e.preventDefault();

    const name = document.getElementById('name').value;
    const rank = document.getElementById('rank').value;

    const response = await fetch('/api/ninjas', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, rank: Number(rank) }),
    });

    if (response.ok) {
        document.getElementById('name').value = '';
        document.getElementById('rank').value = '';
        loadNinjas();  // Refresh the list
    }
});

Deleting a Ninja

async function deleteNinja(id) {
    const response = await fetch(`/api/ninjas/${id}`, {
        method: 'DELETE',
    });

    if (response.ok) {
        loadNinjas();  // Refresh the list
    }
}

CORS Considerations

If your front-end is served from a different origin (different port or domain), you need CORS:

npm install cors
const cors = require('cors');
app.use(cors());

Since we are serving the front-end from the same Express server (express.static), CORS is not needed. But when using a separate React dev server (next episode), CORS is required.

Key Takeaways

  • express.static('public') serves HTML, CSS, and JS files from the public/ folder
  • The Fetch API sends HTTP requests from the browser — fetch() returns a Promise
  • Use response.json() to parse the JSON response body
  • POST and PUT requests need method, headers (Content-Type), and body (JSON string)
  • After creating or deleting data, refresh the displayed list by calling the GET endpoint again
  • CORS is needed when the front-end and API are on different origins