Stop 05 · Express.js & Web FrameworksProjects · 1/3

REST API for Todo App

Part of the Backend Developer Roadmap

In short

The todo API is the 'hello world' of backends for a reason: it uses every CRUD operation. Build it properly once and you'll reuse the pattern in every project.

A full CRUD API for managing todos — the classic first Express project, exercising routing, validation, and connecting to a real database.

The mascot sticks colourful notes on a corkboard and ticks one with a marker.

Think of it like this

The sticky-note board

On your hostel wall, you stick notes, read them, tick some off, and peel others away. Create, read, update, delete. Your todo API does exactly this, except the board is a database and the notes are JSON.

Watch it happen

CRUD in five requests

Client
Todo API
Store

POST /todos

1/6Body { "title": "Submit DBMS assignment" }. The API validates it.

The big ideas

What you need to know

Five endpoints

GET /todos, GET /todos/:id, POST /todos, PATCH /todos/:id, DELETE /todos/:id.

Correct status codes

201 on create, 204 on delete, 404 for a missing id, 400 for a bad body.

Validate every write

Title required and trimmed, sensible max length, done must be a boolean.

Filter the list

Support GET /todos?done=false so the app can show only pending tasks.

See it in code

Walk through the code

js
1const todos = new Map();2let nextId = 1;3app.patch("/todos/:id", (req, res) => {4  const todo = todos.get(Number(req.params.id));5  if (!todo) return res.status(404).json({ error: "Todo not found" });6  const { title, done } = req.body;7  if (title !== undefined && (typeof title !== "string" || !title.trim())) {8    return res.status(400).json({ error: "title must be a non-empty string" });9  }10  if (done !== undefined && typeof done !== "boolean") {11    return res.status(400).json({ error: "done must be true or false" });12  }13  if (title !== undefined) todo.title = title.trim();14  if (done !== undefined) todo.done = done;15  res.json(todo);16});

1/4An in-memory Map is enough to start. Swap it for a database later.

PATCH is the trickiest route: every field is optional, but any field that is sent must still be valid.

Save yourself the pain

Common mistakes

Oops

Returning 200 with an empty body when a todo id doesn't exist.

Do this instead

Return 404 with a clear error. The client needs to tell 'gone' from 'success'.

Oops

Using PUT but only sending one field, wiping the rest.

Do this instead

Use PATCH for partial updates. PUT means 'replace the whole thing'.

Your mission

Milestone 1: working CRUD

~45 min

Quick check

Which status code fits a successful DELETE /todos/1 that returns no body?

Go deeper

  1. 1Implement all 5 REST operations (list, get, create, update, delete) properly.
  2. 2Add request validation and consistent error responses.
  3. 3Connect it to a real database instead of an in-memory array.

More projects at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge