Start.dev
Back to blog

Build a REST API with Node.js and Express

Build your first REST API with Node.js and Express in about 50 lines: routes, JSON, POST, PUT and DELETE, tested with curl, plus where to go next.

Ariel Weinberger
Ariel Weinberger ยท 5 min read

Every app you use talks to a server somewhere. When your phone shows a list of movies or your to-do app saves a task, it is sending a request to an API and getting data back. Building one yourself is one of the most satisfying early wins in web development, because you go from "I write code" to "my code answers other programs."

In this guide you will build a small REST API with Node.js and Express: a bookshelf you can list, read, add to, update and delete from. It is about 50 lines, and you can finish it in an hour.

New to REST? Read How REST APIs work, explained for beginners first. It explains requests, responses and status codes without any code, and this guide puts them to work.

What you need first

You should be comfortable with variables, functions, arrays and objects in JavaScript. If you are still deciding which language to start with, Python vs JavaScript: which should you learn first? will help you choose. There is nothing to install: the code editor, the running server and a tool for sending requests are all in your browser on start.dev.

What a REST API actually is

An API is a set of URLs that return data instead of web pages. REST is a convention for how those URLs behave:

  • The path names the thing you want, like /api/books or /api/books/2.
  • The method says what to do with it: GET reads, POST creates, PUT updates, DELETE removes.
  • The status code tells the client what happened: 200 for success, 201 for created, 404 for not found.

That is the whole idea. If the vocabulary feels fuzzy, the lessons Clients And Servers (opens in a new tab) and Methods And Paths (opens in a new tab) explain it with live requests, and Status Codes (opens in a new tab) covers the codes you will use most.

Step 1: Start your server

Express is the library that does the heavy lifting, and it is already available in the course workspace. (On your own machine you would add it with npm install express.) Start with a server that answers one route:

import express from "express"
 
const app = express()
app.use(express.json())
 
app.get("/", (req, res) => {
  res.send("Hello from the Bookshelf API")
})
 
app.listen(3000, () => {
  console.log("Server running on port 3000")
})

Run it, then use the HTTP Client to send a GET request to /. You should see your message come back with a 200 status. That is a working server.

The course builds this up gradually. Your First Dependency (opens in a new tab) shows what a dependency really is, and Hello Express (opens in a new tab) walks through this exact starting point. The line app.use(express.json()) teaches Express to read JSON request bodies, which you will need in step 3.

Step 2: Read data with GET

Real APIs use a database. To keep things simple, we will store books in an array. Add this above app.listen:

let books = [
  { id: 1, title: "Dune", author: "Frank Herbert" },
  { id: 2, title: "Neuromancer", author: "William Gibson" },
]
let nextId = 3
 
app.get("/api/books", (req, res) => {
  res.json(books)
})
 
app.get("/api/books/:id", (req, res) => {
  const book = books.find((b) => b.id === Number(req.params.id))
  if (!book) {
    return res.status(404).json({ error: "Book not found" })
  }
  res.json(book)
})

The :id in the path is a route parameter. Express puts whatever the client sends into req.params.id, and you use it to find the right book. If nothing matches, you return a 404 instead of pretending everything is fine.

To go deeper, Thinking In Resources (opens in a new tab) explains how to design your paths, Route Params (opens in a new tab) covers params, and When The Id Doesnt Exist (opens in a new tab) is all about handling missing items gracefully.

Send a GET to /api/books/1 to see Dune, then try /api/books/99 to see your 404 in action.

Step 3: Create data with POST

Reading is easy because a plain GET is enough. Creating needs a request body: the data you want to send. First add the route:

app.post("/api/books", (req, res) => {
  const { title, author } = req.body
  if (!title || !author) {
    return res.status(400).json({ error: "title and author are required" })
  }
  const book = { id: nextId++, title, author }
  books.push(book)
  res.status(201).json(book)
})

Then, in the HTTP Client, switch the method dropdown from GET to POST, set the path to /api/books, and put this JSON in the Body:

{ "title": "Hyperion", "author": "Dan Simmons" }

Click Send. You get the new book back with a 201 Created status. Now remove the title and send again: you get a 400 with a helpful message. That check is called validation, and it is the difference between an API that works on your machine and one that survives real users.

The matching lessons are Reading The Body (opens in a new tab), The Create Route (opens in a new tab) and When The Body Is Wrong (opens in a new tab).

Step 4: Update and delete

The last two routes complete the set, often called CRUD (create, read, update, delete):

app.put("/api/books/:id", (req, res) => {
  const book = books.find((b) => b.id === Number(req.params.id))
  if (!book) {
    return res.status(404).json({ error: "Book not found" })
  }
  const { title, author } = req.body
  if (!title || !author) {
    return res.status(400).json({ error: "title and author are required" })
  }
  book.title = title
  book.author = author
  res.json(book)
})
 
app.delete("/api/books/:id", (req, res) => {
  const index = books.findIndex((b) => b.id === Number(req.params.id))
  if (index === -1) {
    return res.status(404).json({ error: "Book not found" })
  }
  books.splice(index, 1)
  res.status(204).end()
})

A successful delete returns 204 No Content: it worked, and there is nothing to send back. See Updating With Put (opens in a new tab) and Delete And 204 (opens in a new tab) for the reasoning behind each choice.

Try them out with the HTTP Client:

  • PUT to /api/books/1 with the body { "title": "Dune Messiah", "author": "Frank Herbert" }, then GET /api/books/1 to see the change.
  • DELETE to /api/books/2, then GET /api/books to confirm it is gone.

Congratulations: that is a complete REST API. Every serious backend you will meet later follows the same pattern, with more routes and a real database behind it. When you reach the database part, SQL for beginners: the 10 queries to learn first is a good place to start.

Common beginner mistakes

  • Forgetting express.json(). Without it, req.body is undefined and your POST route fails in confusing ways.
  • Testing old code. If a request behaves as though your change is not there, make sure the server picked up your latest code before you send it again.
  • Comparing a string to a number. Route params are always strings, which is why the code above wraps them in Number().
  • Always returning 200. Status codes are part of your API's contract. Use 201, 400 and 404 honestly.
  • Putting everything in one file forever. It is fine for a first API, but you will want to split things up soon.

What to build next

This API forgets everything when you stop the server, and anyone can call it. The next steps fix both:

  1. Add middleware for logging, API-key checks and error handling. Read Express Middleware Explained for Beginners for the big picture, then build it yourself, starting with The Pipeline And Next (opens in a new tab).
  2. Organize your code with routers and controllers, starting at The Router (opens in a new tab).
  3. Save data to disk so it survives restarts, beginning with Reading From A File (opens in a new tab).

You can also practice what you just learned on a real project: Project Bookshelf API (opens in a new tab) has you build this same API with guided checks along the way.

Keep going

You now have the shape of every backend: requests come in, your code decides what to do, and JSON goes out. The full course, Building APIs with Node.js & Express (opens in a new tab), takes you from here to a structured, persistent API through hands-on projects, all in the browser.

If any of the JavaScript in this post felt shaky, shore it up with the courses below first. A little more fluency with arrays, objects and functions makes everything on the server side easier.

Level up your coding skills

Jump into interactive courses and start building real-world projects.

Start learning

Related posts

Learn what Express middleware is, how next() moves a request through the pipeline, and how to write a logger, an API-key gate and an error handler.
Ariel Weinberger
Ariel Weinberger ยท 4 min read
Learn how REST APIs work by following one request from client to server and back: URLs, methods, headers, status codes, JSON, and what REST actually means.
Ariel Weinberger
Ariel Weinberger ยท 7 min read
Confused by SQL joins? Learn INNER, LEFT, RIGHT, FULL and CROSS joins with one tiny dataset, plain-English explanations and copy-paste queries.
Ariel Weinberger
Ariel Weinberger ยท 7 min read