Build a backend API with Node.js
Intermediate

Build a backend API with Node.js

In this codelab you'll learn what a backend is, set up a Node.js project with Express, create REST API routes, handle HTTP methods, add middleware, and build a complete CRUD API.

Before you start

This codelab assumes you've completed:

What you'll use

  • Node.js A JavaScript runtime that lets you run JavaScript outside the browser — perfect for building servers. Learn more
  • Express The most popular Node.js framework for building web servers and APIs. Learn more
  • npm The package manager for Node.js — install libraries and manage dependencies. Learn more
30–45 min

1What is a backend?

When you visit a website, everything you see — buttons, text, images — is the frontend. But most apps also have a backend: a server that handles data, business logic, and communication with databases.

The backend receives requests from the frontend (like "show me all the products") and sends back responses (like a list of products in JSON format).

What backends do

  • Store and retrieve data from a database
  • Handle user authentication (login, signup)
  • Process payments and send emails

💡 Think of it this way

If a restaurant is your app, the dining room is the frontend (what customers see) and the kitchen is the backend (where the food is made). The waiter is the API — carrying requests and responses between them.

2What is Express?

Express is a lightweight, flexible framework for Node.js that makes it easy to build web servers and APIs. It's the most widely used Node.js framework, powering millions of applications.

  • Routing Define URL paths and what happens when someone visits them.
  • Middleware Functions that run before your route handlers — great for logging, authentication, and parsing data.
  • JSON handling Built-in support for sending and receiving JSON data.
  • Ecosystem Thousands of npm packages work with Express — from database connectors to authentication libraries.

Express doesn't force you into a specific project structure. You start simple and add complexity only when you need it.

3Create the project

Open your terminal and create a new folder for your API:

Terminal
mkdir my-api && cd my-api
npm init -y
npm install express

This creates a project folder, initializes a package.json, and installs Express. Your folder structure looks like this:

Document contents
my-api/
├── package.json
├── node_modules/
└── server.js        # You'll create this next

💡 Tip: If npm init -y doesn't work, make sure Node.js is installed. Check with node --version.

4Build your first route

Create a file called server.js in your project folder and add the following code:

Document contents
// server.js
const express = require('express');
const app = express();
const PORT = 3000;

// A simple GET route
app.get('/', (req, res) => {
  res.json({ message: 'Hello from my API!' });
});

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

Start the server:

Terminal
node server.js

Open a new terminal and test it:

Terminal
curl http://localhost:3000

You should see:

Terminal
{ "message": "Hello from my API!" }

5Understand routes and HTTP methods

APIs use different HTTP methods for different actions. Here are the most common ones:

MethodPurposeExample
GETRead dataGET /todos
POSTCreate dataPOST /todos
PUTUpdate dataPUT /todos/1
DELETEDelete dataDELETE /todos/1

Each route is a combination of a method and a path. Express makes it easy to define routes for each one.

6Build a CRUD API

Now let's build a complete API for managing a todo list. Replace the contents of server.js with this code:

Document contents
// server.js
const express = require('express');
const app = express();
const PORT = 3000;

// Middleware to parse JSON request bodies
app.use(express.json());

// In-memory data store
let todos = [
  { id: 1, task: 'Learn Express', done: false },
  { id: 2, task: 'Build an API', done: false },
];
let nextId = 3;

// GET all todos
app.get('/todos', (req, res) => {
  res.json(todos);
});

// GET a single todo by ID
app.get('/todos/:id', (req, res) => {
  const todo = todos.find(t => t.id === Number(req.params.id));
  if (!todo) return res.status(404).json({ error: 'Not found' });
  res.json(todo);
});

// POST a new todo
app.post('/todos', (req, res) => {
  const { task } = req.body;
  if (!task) return res.status(400).json({ error: 'Task is required' });
  const todo = { id: nextId++, task, done: false };
  todos.push(todo);
  res.status(201).json(todo);
});

// PUT (update) a todo
app.put('/todos/:id', (req, res) => {
  const todo = todos.find(t => t.id === Number(req.params.id));
  if (!todo) return res.status(404).json({ error: 'Not found' });
  if (req.body.task !== undefined) todo.task = req.body.task;
  if (req.body.done !== undefined) todo.done = req.body.done;
  res.json(todo);
});

// DELETE a todo
app.delete('/todos/:id', (req, res) => {
  const index = todos.findIndex(t => t.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ error: 'Not found' });
  todos.splice(index, 1);
  res.status(204).send();
});

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

This gives you a fully working CRUD (Create, Read, Update, Delete) API. The data lives in memory, so it resets when you restart the server — we'll connect a database in a future codelab.

7Test your API

Restart the server:

Terminal
node server.js

Then try these curl commands in another terminal:

Terminal
# List all todos
curl http://localhost:3000/todos

# Create a new todo
curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{"task": "Deploy my API"}'

# Update a todo
curl -X PUT http://localhost:3000/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

# Delete a todo
curl -X DELETE http://localhost:3000/todos/1

💡 Tip: You can also test APIs with tools like Postman or the VS Code REST Client extension. They give you a visual interface for sending requests.

8Add middleware

Middleware functions run between receiving a request and sending a response. They're useful for logging, authentication, error handling, and more. Here's a simple request logger:

Document contents
// Add this BEFORE your routes
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

You'll also want CORS support so your frontend can talk to this API. Install the cors package:

Terminal
npm install cors
Terminal
const cors = require('cors');

// Allow requests from any origin
app.use(cors());

Now any frontend application can send requests to your API.

💡 What is CORS?

CORS (Cross-Origin Resource Sharing) is a security feature in browsers. By default, a frontend at localhost:5173 can't call an API at localhost:3000. The cors middleware tells the browser it's ok to allow these cross-origin requests.

9What's next

You've built a working REST API! Here are some great next steps:

🔗 Connect a frontend

Wire your API to a React app — Connect frontend to backend

🗄️ Add a database

Replace in-memory storage with a real database using Supabase or Neon

Deploy your API

Put your API online — Deploy web apps with Vercel

🐙 Version control

Track your code with Git — Getting started with GitHub

📖 Lesson: See how backend APIs fit into web application architecture in our Elements of a web application lesson.

🎉

You did it!

You've built a backend API from scratch with Node.js and Express, learned HTTP methods, created CRUD routes, tested with curl, and added middleware. You're ready to build real server-side applications!

Back to codelabs

How was this codelab?

Let us know what you thought — suggestions, issues, or anything else.

Build a backend API with Node.js