Build a REST API with Node.js and Express

Build a CRUD REST API server with Express that manages a book collection.

Introduction

30 Second Summary

Every time you use an app on your phone, check a weather forecast, or scroll through social media, your device is talking to a server behind the scenes. That communication happens through something called an API.

In this project, you will build your own REST API server that manages a personal reading list of books. You'll create endpoints that let you add, view, update, and delete books using simple commands from your terminal.

What You'll Build

A REST API server built with Node.js and Express that handles full CRUD operations for a book collection, storing data in memory.

By the end of this project, you'll have:

  • A running Express server on http://localhost:3000 that responds to HTTP requests.
  • Five API endpoints implementing full CRUD operations (Create, Read, Update, Delete).
  • Hands-on experience testing your API using curl commands from the terminal.
  • Secret Mission: Add a search endpoint that filters books by author or title.

Are there any prerequisites?

None. This project includes full setup instructions for every tool you need, including Node.js and Visual Studio Code. No prior coding experience with JavaScript or APIs is required.

Set Up Your Development Environment

Your tools are ready. Node.js is installed and VS Code is open with a terminal available.

Every Node.js project starts with a folder and a package.json file that tracks metadata and dependencies. In this step, you'll create your project folder, initialize it as a Node.js project, and install Express as your web framework.

In this step, get ready to:
  • Create a project folder on your Desktop.
  • Initialize npm and install Express.
  • Configure your package.json file.
Create your project folder

You need a dedicated folder to hold your API's code and configuration files. Creating it on your Desktop makes it easy to find later.

  • In the VS Code terminal, move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir book-api
cd book-api
  • Confirm the folder exists by running:
ls

The folder is empty for now. That's expected.

Initialize npm and install Express

The npm init command creates a package.json file that identifies your project to Node.js. The -y flag accepts all the defaults so you don't have to answer prompts one by one.

  • Initialize your project by running:
npm init -y
  • You should see output starting with Wrote to followed by the contents of your new package.json.

Seeing an error about missing permissions?

Make sure you ran cd book-api in the previous step. If your terminal is still in ~/Desktop, the command will still work, but double-check you're inside the project folder before continuing.

Help me debug my npm init error.

  • Install Express as a dependency by running:
npm install express

What does this command do?

This downloads the Express package from the npm registry and saves it in a node_modules folder inside your project. It also adds Express as a dependency in your package.json.

  • After the install finishes, you should see a summary showing added followed by the number of packages installed.
  • Confirm Express is installed by running:
ls

You should see node_modules, package.json, and package-lock.json in the output.

npm install failed?

Check that your internet connection is active. The npm install command needs to download files from the npm registry.

If you see a permission error, try closing VS Code and reopening it as an administrator (Windows) or using sudo (macOS).

Help me fix my npm install error.

Configure your package.json

The default package.json has placeholder values and fields you don't need. You'll replace it with a clean version that includes a project description and a start script.

  • Open the book-api folder in VS Code by clicking File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the book-api folder, and click Open.
  • In the Explorer sidebar on the left, click package.json to open it.
  • Select all the content in the file and replace it with the following:
{
  "name": "book-api",
  "version": "1.0.0",
  "description": "A simple REST API for managing a reading list",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "express": "^5.2.1"
  }
}

What does this file do?

  • name and version identify your project.
  • description is a short summary of what your project does.
  • main tells Node.js which file to run when the project starts.
  • scripts defines shortcuts. The start script lets you run your server with npm start later.
  • dependencies lists the packages your project needs. Express ^5.2.1 means any version compatible with 5.2.1.
  • Save package.json by pressing Cmd+S (macOS) or Ctrl+S (Windows).

Seeing red squiggly lines in your JSON?

JSON is strict about formatting. Make sure there are no trailing commas after the last item in an object or array. Every string must be wrapped in double quotes.

Help me fix my package.json syntax error.

✔️ Awesome, I've got everything!

Great. Make sure you've saved your file.

ⓧ I'd like to double check the full code

Here's the complete package.json your file should match:

{
  "name": "book-api",
  "version": "1.0.0",
  "description": "A simple REST API for managing a reading list",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "express": "^5.2.1"
  }
}

Your project folder is set up with Express installed and ready. Next up, you'll create the server file and get it running on your machine.

Create Your First Express Server

Your project folder is ready with Express installed. Now it's time to write the actual server code that will listen for requests and respond to them.

Every web server follows the same basic pattern: start up, listen on a port, and respond when someone visits a URL. In this step, you'll create the file that does exactly that for your Book API.

In this step, get ready to:
  • Create an Express server file with JSON parsing middleware.
  • Add a welcome route that confirms the server is working.
  • Run the server and see it respond in your browser.
Create the server file

Express needs a JavaScript file to define your server's behavior. This file imports Express, sets up middleware, and tells the server which port to listen on.

  • In VS Code's Explorer sidebar (the file icon at the top left), click the New File icon.
  • Name the file index.js and press Enter to create it.
  • Paste the following code into index.js:
const express = require('express');
const app = express();
const port = 3000;

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

// Start the server
app.listen(port, () => {
  console.log(`Book API server running at http://localhost:${port}`);
});

What does this code do?

const express = require('express') imports the Express library you installed in the previous step. const app = express() creates your server instance.

app.use(express.json()) registers middleware that automatically parses incoming JSON request bodies. Without this, your server wouldn't understand data sent by clients.

app.listen(port, ...) tells the server to start accepting connections on port 3000. The callback prints a confirmation message once the server is ready.

  • Save index.js by pressing Cmd+S (macOS) or Ctrl+S (Windows).

You won't see a change yet. Next, you'll add a route so the server has something to respond with when someone visits it.

Add a health check route

A server without routes is like a shop with no doors. Routes define the URLs your server responds to and what it sends back.

  • In index.js, find the line that says // Start the server.
  • Add the following code above that line:
// Welcome route
app.get('/', (req, res) => {
  res.json({ message: 'Welcome to the Book API! Go to /books to see all books.' });
});

What does this route do?

app.get('/', ...) tells Express to listen for GET requests at the root URL (/). When someone visits http://localhost:3000, this handler runs.

res.json(...) sends a JSON response back to the client. This is the standard format for REST API responses.

  • Save index.js.

The server now has a route defined. In the next substep, you'll start it and see the response in your browser.

✔️ Awesome, I've got everything!

Great. Make sure you've saved index.js before moving on.

ⓧ I'd like to double check the full code

const express = require('express');
const app = express();
const port = 3000;

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

// Welcome route
app.get('/', (req, res) => {
  res.json({ message: 'Welcome to the Book API! Go to /books to see all books.' });
});

// Start the server
app.listen(port, () => {
  console.log(`Book API server running at http://localhost:${port}`);
});
Test the server

Time to see your server in action. You'll start it from the terminal and confirm it responds in your browser.

  • Start your server by running this command in the VS Code terminal:
node index.js

You should see this message printed in your terminal:

Book API server running at http://localhost:3000
  • Open your browser and visit http://localhost:3000.

You should see a JSON response that says:

{"message":"Welcome to the Book API! Go to /books to see all books."}

Don't see the welcome message?

  • If you see Cannot GET /, make sure the welcome route is placed above the app.listen() call. Routes defined after the server starts won't register.
  • If the terminal says something about a port already in use, another process is using port 3000. Close other terminal windows or applications that might be running a server.
  • If you see a syntax error, double-check that you used backticks (`) around the template literal in console.log, not regular quotes.

Still stuck? Help me debug why my Express server isn't responding at localhost:3000.

Your server is alive and responding. Next up, you'll add a data store and build the endpoints that let you retrieve books from it.

Build the GET Endpoints

Your server is running and responding with a welcome message. Now it's time to give it some real data to work with.

In this step, you'll add a collection of books to your server's memory and create two GET endpoints that let anyone retrieve that data. These are your first REST API "Read" operations.

In this step, get ready to:
  • Add an in-memory data store of book objects to your server.
  • Create a GET endpoint that returns all books as JSON.
  • Create a GET endpoint that returns a single book by its ID.
Set up in-memory data

Every API needs data to serve. Instead of connecting a database (which adds complexity), you'll store books directly in a JavaScript array. This keeps the focus on learning how Express routes work.

  • In index.js, find the line app.use(express.json()); and add the following code below it, before the welcome route:
// In-memory data store
let books = [
  { id: 1, title: '1984', author: 'George Orwell', year: 1949 },
  { id: 2, title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960 },
  { id: 3, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925 }
];

let nextId = 4;

What does this code do?

The books array holds three book objects, each with an id, title, author, and year property. This is your data store for the entire project.

The nextId variable tracks the next available ID number. When you add new books later, this ensures each book gets a unique identifier.

  • Save index.js.
  • You won't see a change yet. The next chunk adds a route that serves this data.
Create the GET /books route

Your data exists in memory, but there's no way for anyone to access it yet. You need an endpoint that responds to GET requests with the full list of books as JSON.

  • Below the welcome route (the app.get('/') block), add this new route:
// GET all books
app.get('/books', (req, res) => {
  res.json(books);
});

What does this code do?

When someone sends a GET request to /books, Express calls the handler function. res.json(books) converts the books array into a JSON string and sends it back as the response.

Express also sets the Content-Type header to application/json automatically when you use res.json().

  • Save index.js.
  • If your server is still running from earlier, press Ctrl+C in the terminal to stop it.
  • Start the server by running:
node index.js
  • Visit http://localhost:3000/books in your browser. You should see a JSON array containing three book objects.

Don't see your books?

  • Make sure you saved index.js before restarting the server.
  • Check that the books array is placed above the route that references it. JavaScript reads top to bottom.
  • Confirm your terminal shows Book API server running at http://localhost:3000 with no errors.

Still stuck? Why isn't my /books endpoint returning data?

Create the GET /books/:id route

Returning all books is useful, but clients often need a specific book. A parameterized route lets you extract an ID from the URL and return just one result.

  • Below the GET /books route you just added, add this route:
// GET a single book by ID
app.get('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ error: 'Book not found' });
  }
  res.json(book);
});

What does this code do?

  • :id in the route path is a URL parameter. Express captures whatever value appears in that position and stores it in req.params.id.
  • parseInt(req.params.id) converts the string from the URL into a number so it can match the numeric id in your books array.
  • If no book matches, the server responds with a 404 status code and a JSON error message. This tells the client the resource doesn't exist.
  • Save index.js.
  • Stop the server with Ctrl+C and restart it by running:
node index.js
  • Visit http://localhost:3000/books/1 in your browser. You should see a single JSON object for "1984" by George Orwell.
  • Now visit http://localhost:3000/books/99. You should see the error response: {"error":"Book not found"}.

Seeing an unexpected error?

  • If you see Cannot GET /books/1, make sure your route uses '/books/:id' with the colon before id.
  • If you get all three books instead of just one, check that parseInt(req.params.id) is being compared with === (strict equality), not ==.
  • If the response is always the 404 error, confirm you used b.id === parseInt(req.params.id) inside .find().

Still stuck? Why is my /books/:id route not finding the book?

✔️ Awesome, I've got everything!

Great. Double check you've saved index.js and your server is running without errors.

ⓧ I'd like to double check the full code

Here's the complete index.js at this point:

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 books = [
  { id: 1, title: '1984', author: 'George Orwell', year: 1949 },
  { id: 2, title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960 },
  { id: 3, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925 }
];

let nextId = 4;

// Welcome route
app.get('/', (req, res) => {
  res.json({ message: 'Welcome to the Book API! Go to /books to see all books.' });
});

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

// GET a single book by ID
app.get('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ error: 'Book not found' });
  }
  res.json(book);
});

// Start the server
app.listen(port, () => {
  console.log(`Book API server running at http://localhost:${port}`);
});

Your API can now read data. Next up, you'll build the POST endpoint so clients can add new books to your collection.

Build the POST Endpoint

Your API can read books, but a reading list isn't much use if you can't add new ones to it.

In this step, you'll build a POST endpoint that accepts JSON data from a client and adds a new book to your collection. You'll also add input validation so the server rejects incomplete requests with a helpful error message.

In this step, get ready to:
  • Create a POST /books route that adds new books to your array.
  • Add validation that rejects requests missing a title or author.
  • Test your endpoint using curl commands from the terminal.
Create the POST /books route

GET endpoints only read data. A POST endpoint lets clients send new data to the server inside the request body.

  • In index.js, find the comment that says // Start the server.
  • Add the following POST route above that line:
// POST a new book
app.post('/books', (req, res) => {
  const { title, author, year } = req.body;

  const newBook = {
    id: nextId++,
    title,
    author,
    year: year || null
  };

  books.push(newBook);
  res.status(201).json(newBook);
});

What does this code do?

This route listens for POST requests at /books. When a request arrives, it pulls title, author, and year out of the request body using destructuring.

  • id: nextId++ assigns a unique ID and then increments the counter for next time.
  • year: year || null makes the year field optional. If the client doesn't provide one, it defaults to null.
  • res.status(201).json(newBook) sends back the created book with a 201 status code, which means "resource created successfully."
  • Save index.js.

You won't see a change yet because POST routes can't be tested in a browser. The curl test in a moment will confirm it works.

Add input validation

Without validation, a client could send an empty request and your server would happily create a book with no title or author. A good API tells the client exactly what went wrong.

  • In index.js, find the POST route you just added.
  • Find this line:
  const { title, author, year } = req.body;
  • Add the following validation check directly below it (before const newBook):
  if (!title || !author) {
    return res.status(400).json({ error: 'Title and author are required' });
  }

What does this validation do?

The if (!title || !author) check catches two cases: when the field is missing entirely, or when it's an empty string.

Returning a 400 status code means "bad request." The JSON error message tells the client exactly which fields they forgot, so they can fix the request and try again.

  • Save index.js.

You'll test both the happy path and the validation in the next substep.

Test with curl

Your POST route is ready. Time to prove it works by sending requests from the terminal.

  • If your server is still running from the previous step, press Ctrl+C in the terminal to stop it.
  • Start the server again with the updated code by running:
node index.js
  • Open a second terminal in VS Code by clicking Terminal in the top menu bar, then New Terminal.
  • Test adding a new book by running this curl command:

macOS

curl -X POST http://localhost:3000/books -H "Content-Type: application/json" -d '{"title": "Dune", "author": "Frank Herbert", "year": 1965}'

Windows

curl -X POST http://localhost:3000/books -H "Content-Type: application/json" -d "{\"title\": \"Dune\", \"author\": \"Frank Herbert\", \"year\": 1965}"

You should see the newly created book returned as JSON with id: 4 and a 201 status.

  • Verify the book was added to the collection by running:
curl http://localhost:3000/books

You should see all four books in the response, including the new "Dune" entry at the end.

  • Now test the validation by sending a request with a missing author:

macOS

curl -X POST http://localhost:3000/books -H "Content-Type: application/json" -d '{"title": "Incomplete Book"}'

Windows

curl -X POST http://localhost:3000/books -H "Content-Type: application/json" -d "{\"title\": \"Incomplete Book\"}"

You should see the 400 error response: {"error":"Title and author are required"}.

Seeing a different error?

  • If you see Cannot POST /books, make sure you saved index.js and restarted the server with Ctrl+C then node index.js.
  • If the JSON looks garbled on Windows, check that you escaped the quotes correctly with backslashes.
  • If you get undefined for all fields, make sure app.use(express.json()) appears before your routes in index.js.

Still stuck? Help me debug my POST /books endpoint

✔️ Awesome, I've got everything!

Great. Double check you've saved index.js and your curl responses match what's described above.

ⓧ I'd like to double check the full code

Here is the complete index.js file at this point:

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 books = [
  { id: 1, title: '1984', author: 'George Orwell', year: 1949 },
  { id: 2, title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960 },
  { id: 3, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925 }
];

let nextId = 4;

// Welcome route
app.get('/', (req, res) => {
  res.json({ message: 'Welcome to the Book API! Go to /books to see all books.' });
});

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

// GET a single book by ID
app.get('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ error: 'Book not found' });
  }
  res.json(book);
});

// POST a new book
app.post('/books', (req, res) => {
  const { title, author, year } = req.body;

  if (!title || !author) {
    return res.status(400).json({ error: 'Title and author are required' });
  }

  const newBook = {
    id: nextId++,
    title,
    author,
    year: year || null
  };

  books.push(newBook);
  res.status(201).json(newBook);
});

// Start the server
app.listen(port, () => {
  console.log(`Book API server running at http://localhost:${port}`);
});

Your API can now create new resources. Next up, you'll build the PUT and DELETE endpoints to complete the full CRUD cycle.

Build the PUT and DELETE Endpoints

Your API can now create and read books. But what happens when a book title has a typo, or you finish a book and want to remove it from your list?

In this step, you'll add the final two CRUD operations: Update and Delete. These map directly to the PUT and DELETE HTTP methods.

In this step, get ready to:
  • Create a PUT endpoint to update existing books.
  • Create a DELETE endpoint to remove books from the array.
  • Test the full CRUD cycle using curl commands.
Create the PUT route to update books

A PUT request tells your server to replace or update an existing resource. Your PUT route will find a book by its ID, update only the fields the client sends, and return the updated book.

  • In index.js, find the closing }); of your POST route (the one after res.status(201).json(newBook);).
  • Add the PUT route below it by copying this code before the // Start the server comment:
// PUT (update) a book by ID
app.put('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ error: 'Book not found' });
  }

  const { title, author, year } = req.body;
  if (title) book.title = title;
  if (author) book.author = author;
  if (year) book.year = year;

  res.json(book);
});

What does this code do?

  • books.find() locates the book with the matching ID, just like your GET-by-ID route.
  • The if (title) checks only update fields that the client actually sent. This means you can update just the title without touching the author or year.
  • res.json(book) returns the updated book so the client can confirm the changes.
  • Save index.js.

You won't see a change yet. The next chunk adds the DELETE route, and then you'll test both together.

Seeing a red underline or syntax error?

Make sure the new code sits between the closing }); of the POST route and the // Start the server comment. A misplaced brace will break the file.

Check that you have matching opening and closing braces for the app.put() callback function.

Why is my PUT route causing a syntax error in VS Code?

Create the DELETE route to remove books

A DELETE request removes a resource from the server. This route uses findIndex() instead of find() because you need the array position to remove the element with splice().

  • In index.js, add the DELETE route directly below your PUT route's closing }); and before the // Start the server comment:
// DELETE a book by ID
app.delete('/books/:id', (req, res) => {
  const index = books.findIndex(b => b.id === parseInt(req.params.id));
  if (index === -1) {
    return res.status(404).json({ error: 'Book not found' });
  }

  books.splice(index, 1);
  res.json({ message: 'Book deleted successfully' });
});

What does this code do?

  • findIndex() returns the position of the matching book in the array, or -1 if no match exists.
  • splice(index, 1) removes exactly one element at that position, permanently deleting the book from memory.
  • The response sends a JSON confirmation message so the client knows the deletion succeeded.
  • Save index.js.

You now have all five routes in place. Time to test the full CRUD cycle.

Seeing unexpected token errors?

Count your curly braces. The DELETE route needs an opening { after (req, res) => and a closing }); at the end.

Make sure you didn't accidentally paste the DELETE route inside the PUT route's function body.

Help me fix a syntax error in my Express DELETE route.

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on to testing.

ⓧ I'd like to double check the full code

Here is the complete index.js file with all five routes:

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 books = [
  { id: 1, title: '1984', author: 'George Orwell', year: 1949 },
  { id: 2, title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960 },
  { id: 3, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925 }
];

let nextId = 4;

// Welcome route
app.get('/', (req, res) => {
  res.json({ message: 'Welcome to the Book API! Go to /books to see all books.' });
});

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

// GET a single book by ID
app.get('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ error: 'Book not found' });
  }
  res.json(book);
});

// POST a new book
app.post('/books', (req, res) => {
  const { title, author, year } = req.body;

  if (!title || !author) {
    return res.status(400).json({ error: 'Title and author are required' });
  }

  const newBook = {
    id: nextId++,
    title,
    author,
    year: year || null
  };

  books.push(newBook);
  res.status(201).json(newBook);
});

// PUT (update) a book by ID
app.put('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ error: 'Book not found' });
  }

  const { title, author, year } = req.body;
  if (title) book.title = title;
  if (author) book.author = author;
  if (year) book.year = year;

  res.json(book);
});

// DELETE a book by ID
app.delete('/books/:id', (req, res) => {
  const index = books.findIndex(b => b.id === parseInt(req.params.id));
  if (index === -1) {
    return res.status(404).json({ error: 'Book not found' });
  }

  books.splice(index, 1);
  res.json({ message: 'Book deleted successfully' });
});

// Start the server
app.listen(port, () => {
  console.log(`Book API server running at http://localhost:${port}`);
});
Test the full CRUD cycle

You'll now walk through the complete lifecycle of a book: create it, read it, update it, and delete it. This proves every endpoint works together.

  • If your server is still running from the previous step, stop it by pressing Ctrl+C in the terminal.
  • Start the server again by running:
node index.js

You should see Book API server running at http://localhost:3000 in your terminal.

  • Open a second terminal in VS Code by clicking Terminal in the top menu bar, then New Terminal.
  • Create a new book by running this curl command:

macOS

curl -X POST http://localhost:3000/books -H "Content-Type: application/json" -d '{"title":"Dune","author":"Frank Herbert","year":1965}'

Windows

curl.exe -X POST http://localhost:3000/books -H "Content-Type: application/json" -d "{\"title\":\"Dune\",\"author\":\"Frank Herbert\",\"year\":1965}"

You should see the new book returned with "id":4 and a 201 status.

  • Read the book you just created by running:
curl http://localhost:3000/books/4

You should see the full Dune book object returned as JSON.

  • Update the book's title by running:

macOS

curl -X PUT http://localhost:3000/books/4 -H "Content-Type: application/json" -d '{"title":"Dune Messiah"}'

Windows

curl.exe -X PUT http://localhost:3000/books/4 -H "Content-Type: application/json" -d "{\"title\":\"Dune Messiah\"}"

The response shows the book with its title changed to Dune Messiah, while author and year remain unchanged.

  • Delete the book by running:
curl -X DELETE http://localhost:3000/books/4

You should see {"message":"Book deleted successfully"} confirming the book was removed.

  • Verify the deletion by trying to read the same book again:
curl http://localhost:3000/books/4

This time you should see {"error":"Book not found"} with a 404 status. The book is gone.

Why does this prove your API works?

You just completed a full CRUD cycle: Create (POST), Read (GET), Update (PUT), Delete (DELETE). This is the same pattern that powers every web application backend, from social media feeds to e-commerce stores.

The 404 response on the final GET confirms the data was truly removed from memory, not just hidden.

Getting connection refused or empty responses?

Make sure your server is running in the first terminal. You should see the Book API server running message there.

If you see Cannot PUT /books/4, you likely forgot to stop and restart the server after adding the new routes. Press Ctrl+C in the server terminal and run node index.js again.

My curl commands aren't getting responses from my Express server.

Secret mission

Add a Search Endpoint

Your API can create, read, update, and delete books. But what if someone has hundreds of books and wants to find one by a specific author? Add a search endpoint that filters books by author or title using query parameters.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • The book-api project folder on your Desktop (includes index.js, package.json, and node_modules/).
  • Node.js installed on your system.
  • Visual Studio Code installed on your system.

Keep everything running

No action needed. Choose this if you're still actively building or plan to extend the API with new features.

  • Your book-api folder stays on your Desktop, ready for the next time you open it.
  • Node.js and VS Code remain installed for future projects.
  • If your server is still running in the terminal, you can leave it running or stop it with Ctrl+C when you're done.

Pause - I'll come back to this later

Stop the running server process to free up your terminal. Your project files stay on disk.

  • Switch to the terminal where your server is running.
  • Press Ctrl+C to stop the server.
  • Your book-api folder and all its files remain on your Desktop. When you're ready to resume, open the folder in VS Code and run node index.js again.

Delete - I don't want to use this again

Remove all project files and optionally uninstall the tools you set up.

  • If your server is still running, press Ctrl+C in the terminal to stop it.
  • Delete the project folder by running the appropriate command for your operating system.

macOS

cd ~/Desktop
rm -rf book-api

Windows

cd ~\Desktop
Remove-Item -Recurse -Force book-api
  • To uninstall Node.js:
  • On macOS, remove Node.js by deleting the files installed by the package (see the Node.js download page for details on your installation method).
  • On Windows, open Settings, select Apps, then Installed apps. Find Node.js in the list and click Uninstall.
  • To uninstall VS Code:
  • On macOS, open Finder, go to Applications, and drag Visual Studio Code to the Trash.
  • On Windows, open Settings, select Apps, then Installed apps. Find Microsoft Visual Studio Code and click Uninstall.

Nice Work!

Nice Work!

You just built a fully functional REST API from scratch using Node.js and Express. Your server handles the complete lifecycle of managing data through HTTP requests.

You've learned how to:

  • Build a REST API server with Express that implements five CRUD endpoints (GET all, GET by ID, POST, PUT, and DELETE) for managing a collection of books.
  • Use Express middleware (express.json()) to parse incoming JSON request bodies and handle the request/response cycle.
  • Test API endpoints using curl commands directly from the terminal to send GET, POST, PUT, and DELETE requests.
  • Secret Mission: Added a search endpoint with query parameter filtering for case-insensitive matching by author or title.

Ready to quiz yourself?