Build a REST API with Node.js
Build a Task Manager REST API with full CRUD operations using Express.
Introduction
30 Second Summary
Every time you open an app and see your to-do list load, that data travels from a server to your screen through an API. APIs are how applications send and receive information.
In this project, you will build a REST API from scratch using Node.js and Express. Your API will manage a collection of tasks, responding to requests to create, read, update, and delete them.
What You'll Build
A Task Manager REST API that handles all four CRUD operations (Create, Read, Update, Delete) for managing tasks, running locally on your machine.
By the end of this project, you'll have:
- A Node.js project with an Express server listening on port 3000.
- A full set of CRUD endpoints (GET, POST, PUT, DELETE) that manage tasks with proper HTTP status codes.
- Tested API responses using a browser and curl commands, confirming correct JSON data comes back.
- Secret Mission: Add filtering and search so you can query tasks by completion status or search by keyword.
Are there any prerequisites?
You only need basic familiarity with JavaScript (variables, functions, objects, arrays). No backend experience is needed.
Before We Start
Before We Start...
Set Up Your Environment
Before you can build your REST API, you need a runtime to execute JavaScript outside the browser and a framework to handle HTTP requests.
In this step, you will install Node.js (the runtime), set up VS Code (your code editor), and initialize a new project with Express (the framework that makes building APIs fast and simple).
In this step, get ready to:
- Install Node.js and verify it works.
- Create a project folder and open it in VS Code.
- Initialize a Node.js project and install Express.
Download and install Node.js
Node.js lets you run JavaScript on your computer outside of a browser. Your API server will be a Node.js program, so you need it installed first.
- Open your browser and go to the Node.js download page:
- https://nodejs.org/en/download
- Click the LTS tab (this is the stable, recommended version).
- Download the installer for your operating system.
- Run the installer and accept all the default options by clicking Next at each screen.
What is Node.js?
JavaScript was originally built to run only in web browsers. Node.js takes the same language and lets you run it directly on your computer, which means you can use JavaScript to build servers, command-line tools, and APIs.
After installation completes, you need to verify that Node.js is working.
- Open a new terminal window. Press the Windows key (Windows) or Cmd+Space (macOS) to open your search bar.
- Type Command Prompt (Windows) or Terminal (macOS) and press Enter to open it.
- Check your Node.js version by running this command:
node --version
- Check that npm (Node's package manager) is also available by running:
npm --version
✔️ I see version 24 or higher
You should see something like v24.16.0 for Node and a number like 11.x.x for npm.
Node.js is ready to go. Move on to the next substep.
ⓧ I see an older version
Your computer has an older version of Node.js installed. You need version 24 or higher for this project.
- Go to https://nodejs.org/en/download and download the LTS installer.
- Run the installer. It will upgrade your existing installation automatically.
- Close your terminal completely and open a new one.
- Run node --version again. You should now see v24 or higher.
ⓧ Command not found
Node.js is not installed on your computer yet.
- Go to https://nodejs.org/en/download and click the LTS tab.
- Download the installer for your operating system.
- Run the installer and accept all defaults.
- Close your terminal completely and open a new one. This is required for the system to recognize the new installation.
- Run node --version again. You should now see v24 or higher.
Open VS Code and create your project folder
VS Code is a free code editor that includes a built-in terminal. You will write all your code and run commands from inside it.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Visual Studio Code and press Enter to open it.
Don't have VS Code yet?
Download it for free from https://code.visualstudio.com. Run the installer, accept defaults, and then open it using the search method above.
Now you need to create a folder for your project and open it in VS Code.
- In VS Code, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop in the file dialog.
- Click New Folder (or right-click and select New Folder).
- Name the folder task-api and press Enter.
- Select the task-api folder and click Open (or Select Folder on Windows).
VS Code should now show task-api in the Explorer sidebar on the left. The folder is empty for now.
- Open the integrated terminal by pressing Ctrl+` (that's the backtick key, above Tab on your keyboard).
A terminal panel opens at the bottom of VS Code. It should already be inside your task-api folder.
Terminal not in the right folder?
If the terminal path does not show task-api at the end, it might have opened in a different location. Close the terminal panel, make sure your task-api folder is the one open in VS Code (check the Explorer sidebar), and reopen the terminal with Ctrl+`.
Still stuck? Help me get my VS Code terminal into the right folder.
Initialize your project and install Express
Every Node.js project starts with a package.json file that tracks your project's name, version, and dependencies. The npm init command creates this file for you.
- Initialize your project by running this command in the VS Code terminal:
npm init -y
What does this command do?
The -y flag tells npm to accept all the default values (project name, version, license) without asking you questions one by one. It creates a ready-to-use package.json instantly.
You should see a new package.json file appear in the Explorer sidebar.
Now you need to install Express, the framework that provides routing and HTTP handling for your API.
- Install Express by running this command:
npm install express
What does this command do?
This downloads the Express package from the npm registry and adds it to your project. npm saves it as a dependency in package.json so anyone else working on this project knows it needs Express.
You will also see a new node_modules folder appear. This is where npm stores the downloaded packages.
- Confirm the install worked by checking that package.json now lists Express as a dependency. Click on package.json in the Explorer sidebar to open it.
You should see a "dependencies" section that includes "express" with a version number.
Don't see express in dependencies?
Make sure you ran npm install express (not just npm install). The package name express must be included after install.
Also confirm your terminal is inside the task-api folder. If it ran in the wrong directory, the package.json and node_modules were created elsewhere.
Help me fix my Express installation.
✔️ Awesome, I've got everything!
Great. Double check you have package.json, package-lock.json, and a node_modules folder all visible in the Explorer sidebar.
ⓧ I'd like to double check the full code
Your package.json should look similar to this. The exact version number next to express may differ slightly depending on when you install.
{
"name": "task-api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^5.2.1"
}
}
Your environment is ready. You have Node.js running, a project folder set up, and Express installed. Next up, you will create your first server and see it respond to a real HTTP request.
Create Your First Server
Your environment is locked and loaded. Node.js is installed, Express is ready, and your project folder is open in VS Code.
Now it's time to write the actual server. A server is a program that waits for incoming requests and sends back responses. You'll write one that listens on a specific port and responds with structured JSON data.
In this step, get ready to:
- Create a server file and configure Express.
- Add a welcome route that responds with JSON.
- Start the server and confirm it works in your browser.
Create the server file and set up Express
Every Express server starts with a few lines: import Express, create an application instance, add middleware for parsing request bodies, and tell the server which port to listen on.
- In the VS Code Explorer sidebar on the left, hover over the task-api folder name and click the New File... icon (a page with a plus sign).
- Type server.js and press Enter.
- Paste the following code into server.js:
const express = require('express');
const app = express();
const port = 3000;
// Parse incoming JSON request bodies
app.use(express.json());
What does this code do?
- const express = require('express') imports the Express library you installed in Step 1.
- const app = express() creates your application instance. This is the object you'll attach routes to.
- const port = 3000 sets the port your server will listen on. Port 3000 is a common choice for local development.
- app.use(express.json()) adds middleware that automatically parses JSON in incoming request bodies so you can read them later.
- Save server.js with Ctrl+S.
- You should see server.js listed in the Explorer sidebar on the left.
Don't see server.js in the sidebar?
- Make sure you created the file inside the task-api folder, not outside it. If the file ended up in the wrong location, drag it into task-api in the Explorer.
- If the Explorer panel is hidden, press Ctrl+Shift+E to show it.
Still stuck? Help me find where my file was created.
Add a welcome route
A route tells your server how to respond when someone visits a specific URL. You'll add a root route that sends back a welcome message, plus the app.listen() call that starts the server.
- In server.js, add the following code below the app.use(express.json()) line:
// Root route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the Task Manager API' });
});
app.listen(port, () => {
console.log(`Task Manager API running on http://localhost:${port}`);
});
What does this code do?
- app.get('/', ...) defines a route that responds to GET requests at the root URL (/). When someone visits your server's base address, this function runs.
- res.json(...) sends a JSON response back to the client. The browser will display this structured data.
- app.listen(port, ...) starts the server and tells it to listen on port 3000. The callback logs a confirmation message so you know it's running.
- Save server.js with Ctrl+S.
Seeing a red underline or error in the editor?
- Check that the code you added appears below app.use(express.json()); and not inside it.
- Make sure every opening brace { has a matching closing brace }, and every opening parenthesis ( has a matching ).
- Confirm the template literal in console.log uses backticks (`) and not regular quotes.
Need help? Debug my server.js syntax error.
✔️ Awesome, I've got everything!
Great. Make sure you've saved server.js and you're ready to start the server.
ⓧ I'd like to double check the full code
Here is the complete server.js at this point:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
// Root route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the Task Manager API' });
});
app.listen(port, () => {
console.log(`Task Manager API running on http://localhost:${port}`);
});
Start the server and test it
Your server file is ready. Time to boot it up and see your first REST API response in action.
- Start the server by running this command in your integrated terminal:
node server.js
- You should see this message in the terminal:
Task Manager API running on http://localhost:3000
What does this mean?
Your server is now running and waiting for requests on port 3000. The terminal will stay occupied while the server is active. You'll use a separate browser window to talk to it.
- Open your web browser.
- Type http://localhost:3000 in the address bar and press Enter.
- You should see a JSON response on the page:
{"message":"Welcome to the Task Manager API"}
That JSON is your server talking back. You just sent your first HTTP request and received a structured response.
Not seeing the JSON response?
- Check your terminal for error messages. A common one is Cannot find module 'express'. This means Express did not install correctly. Run npm install express again in the task-api folder.
- If you see EADDRINUSE, something else is already using port 3000. Close other terminal windows or applications that might be running a server.
- Make sure the URL in your browser is exactly http://localhost:3000 with no trailing slash or extra path.
Still stuck? Help me get my Express server running on localhost.
Your server is alive and responding. Next up, you'll add real data and build the endpoints that let you retrieve tasks from your API.
Build the GET Endpoints
Your server is running and responding to requests at the root path. Now it needs actual data to serve.
In this step, you'll create an in-memory data store of tasks and build two GET endpoints. One returns the full list of tasks, and the other returns a single task by its ID.
In this step, get ready to:
- Create an in-memory array of sample tasks.
- Build a GET endpoint that returns all tasks.
- Build a GET endpoint that returns a single task by ID.
Add sample tasks and the GET /tasks route
Before your API can return task data, you need tasks to return. You'll store them in a simple JavaScript array that lives in memory.
- In server.js, find the line that says // Root route. Add the following code above that line:
let tasks = [
{ id: 1, title: 'Buy groceries', completed: false },
{ id: 2, title: 'Walk the dog', completed: true },
{ id: 3, title: 'Read a book', completed: false }
];
let nextId = 4;
- Now, scroll down past the root route's closing });. Add the GET /tasks route below it:
// GET all tasks
app.get('/tasks', (req, res) => {
res.status(200).json(tasks);
});
What does this code do?
- tasks is an array of three sample task objects. Each has an id, a title, and a completed status.
- nextId tracks what ID to assign to the next new task. It starts at 4 because you already have tasks 1, 2, and 3.
- The GET /tasks route responds with the full array as JSON and an HTTP status code of 200 (meaning "OK").
- Save server.js.
- If your server is still running from the previous step, press Ctrl+C in the terminal to stop it.
- Restart the server by running:
node server.js
- Open your browser and visit http://localhost:3000/tasks. You should see a JSON array with three task objects.
Not seeing the tasks array?
- Make sure you saved server.js before restarting the server.
- Check that the tasks array is placed above the root route, not inside it.
- Confirm the URL is exactly http://localhost:3000/tasks with no trailing slash or typos.
Still stuck? Why is my /tasks endpoint not returning data?
Add the GET /tasks/:id route
Returning all tasks is useful, but clients often need just one specific task. A route parameter lets you capture a value from the URL and use it to look up a single item.
- In server.js, find the GET /tasks route you just added. Add the following code below its closing });:
// GET a single task by ID
app.get('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.status(200).json(task);
});
What does this code do?
- :id in the path is a route parameter. When someone visits /tasks/2, Express captures 2 and stores it in req.params.id.
- parseInt(req.params.id) converts the string from the URL into a number so it can match against the numeric id values in the tasks array.
- If no task matches, the route responds with status 404 and an error message. 404 means "not found".
- Save server.js.
- Press Ctrl+C to stop the server, then restart it:
node server.js
- Visit http://localhost:3000/tasks/1 in your browser. You should see a single task object: { "id": 1, "title": "Buy groceries", "completed": false }.
Seeing "Cannot GET /tasks/1"?
- Make sure you restarted the server after saving. Code changes only take effect after a restart.
- Check that app.get('/tasks/:id', ...) is placed below the app.get('/tasks', ...) route, not inside it.
Need more help? Why is my /tasks/:id route not working?
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
let tasks = [
{ id: 1, title: 'Buy groceries', completed: false },
{ id: 2, title: 'Walk the dog', completed: true },
{ id: 3, title: 'Read a book', completed: false }
];
let nextId = 4;
// Root route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the Task Manager API' });
});
// GET all tasks
app.get('/tasks', (req, res) => {
res.status(200).json(tasks);
});
// GET a single task by ID
app.get('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.status(200).json(task);
});
app.listen(port, () => {
console.log(`Task Manager API running on http://localhost:${port}`);
});
Test both endpoints
Your two GET routes are in place. Let's confirm the error handling works too by requesting a task that does not exist.
- Visit http://localhost:3000/tasks in your browser. You should see all three tasks in the array.
- Visit http://localhost:3000/tasks/2. You should see only the "Walk the dog" task.
- Visit http://localhost:3000/tasks/999. You should see { "error": "Task not found" } because no task has that ID.
Why does /tasks/999 return a 404?
Your code searches the tasks array for a task with id 999. When .find() returns undefined, the if (!task) check triggers and sends back a 404 status with an error message.
This pattern protects your API from crashing when someone requests a resource that does not exist.
Your API can now read data. Next up, you'll build the POST endpoint so clients can create new tasks.
Build the POST Endpoint
Your API can read tasks, but it cannot create new ones yet. So far, the server only responds to GET requests.
In this step, you will add a POST endpoint that accepts JSON data from the client and adds a brand-new task to the array. This is the "Create" part of CRUD operations.
In this step, get ready to:
- Add a POST route that creates a new task from request body data.
- Test the endpoint with a curl command.
- Confirm the new task appears alongside existing tasks.
Add the POST route to your server
When a client sends a POST request, it includes data in the request body. Your server needs to read that data, build a new task object, and store it.
- In server.js, find the app.listen line at the bottom of your file.
- Add the following code above it:
// POST a new task
app.post('/tasks', (req, res) => {
const { title } = req.body;
if (!title) {
return res.status(400).json({ error: 'Title is required' });
}
const newTask = {
id: nextId++,
title: title,
completed: false
};
tasks.push(newTask);
res.status(201).json(newTask);
});
What does this code do?
- const { title } = req.body pulls the title field out of the JSON the client sent in the request body.
- The if (!title) check returns a 400 status ("bad request") if no title was provided. This prevents empty tasks from being created.
- nextId++ assigns the current value of nextId as the new task's ID, then increments the counter for next time.
- res.status(201).json(newTask) sends back the newly created task with a 201 status code, which means "resource created".
- Save server.js.
- If your server is still running from the previous step, stop it by pressing Ctrl+C in the terminal.
- Restart the server by running:
node server.js
- You should see Task Manager API running on http://localhost:3000 printed in the terminal with no errors.
Seeing a syntax error?
Make sure the new app.post block is placed before the app.listen line, not inside another route's curly braces.
Check that every opening brace { and parenthesis ( has a matching closing one.
Help me fix a syntax error in my Express POST route
Test the POST endpoint with curl
You cannot test a POST request by typing a URL into the browser. Browsers only send GET requests from the address bar. Instead, you will use curl, a command-line tool for sending HTTP requests.
- Open a second terminal window. Keep the first terminal running your server.
- Send a POST request to create a new task by running this command:
curl -X POST http://localhost:3000/tasks -H "Content-Type: application/json" -d "{\"title\": \"Learn REST APIs\"}"
What does this command do?
- -X POST tells curl to send a POST request instead of the default GET.
- -H "Content-Type: application/json" sets a header telling the server that the body contains JSON data.
- -d sends the JSON body with your new task's title.
- You should see a JSON response like this:
{"id":4,"title":"Learn REST APIs","completed":false}
The response confirms your task was created with ID 4 and completed set to false.
Not seeing a response?
Make sure your server is still running in the other terminal window. If you accidentally closed it, restart it with node server.js.
Double-check that your curl command has matching escaped quotes around the JSON body. A missing backslash before any inner quote will cause a parse error.
Help me troubleshoot my curl POST request
Confirm the task was saved
- Open your browser and navigate to http://localhost:3000/tasks.
You should see the new task (Learn REST APIs) in the array alongside the three sample tasks. This confirms that the POST route successfully pushed the new task into the tasks array.
Why does refreshing the browser work here?
Visiting a URL in the browser sends a GET request. Since you already built a GET /tasks route in the previous step, the browser fetches the full task list for you. The new task shows up because it now lives in the same in-memory array.
✔️ Awesome, I've got everything!
Great. Double check you have saved server.js and your server is running without errors.
ⓧ I'd like to double check the full code
Here is the complete server.js file as it should look at the end of this step:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
let tasks = [
{ id: 1, title: 'Buy groceries', completed: false },
{ id: 2, title: 'Walk the dog', completed: true },
{ id: 3, title: 'Read a book', completed: false }
];
let nextId = 4;
// Root route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the Task Manager API' });
});
// GET all tasks
app.get('/tasks', (req, res) => {
res.status(200).json(tasks);
});
// GET a single task by ID
app.get('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.status(200).json(task);
});
// POST a new task
app.post('/tasks', (req, res) => {
const { title } = req.body;
if (!title) {
return res.status(400).json({ error: 'Title is required' });
}
const newTask = {
id: nextId++,
title: title,
completed: false
};
tasks.push(newTask);
res.status(201).json(newTask);
});
app.listen(port, () => {
console.log(`Task Manager API running on http://localhost:${port}`);
});
Your API can now create tasks on demand. Next up, you will add PUT and DELETE endpoints to update and remove tasks, completing the full set of CRUD operations.
Build the PUT and DELETE Endpoints
Your API can now create and read tasks. Two operations remain to complete the full CRUD cycle: updating existing tasks and deleting ones you no longer need.
In this step, you will add a PUT endpoint to modify task data and a DELETE endpoint to remove tasks entirely. Once these are in place, your API will handle every standard operation a client could request.
In this step, get ready to:
- Update existing tasks with a PUT endpoint.
- Remove tasks with a DELETE endpoint.
- Test both endpoints with curl commands.
Add the PUT route to update tasks
The PUT method lets a client send updated data for an existing resource. Your route needs to find the task, apply any changes, and send back the updated version.
- In server.js, find the closing }); of your POST route (the one just above app.listen).
- Add the following PUT route below it:
// PUT (update) a task by ID
app.put('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
if (req.body.title !== undefined) {
task.title = req.body.title;
}
if (req.body.completed !== undefined) {
task.completed = req.body.completed;
}
res.status(200).json(task);
});
What does this code do?
- app.put('/tasks/:id', ...) listens for PUT requests at a URL like /tasks/1. The :id portion is a URL parameter.
- tasks.find(...) searches the array for a task matching the parsed integer ID. If nothing matches, the route returns a 404 error.
- The two if checks only update a field when the client actually sends it. This means a client can update just the title, just the completed status, or both at once.
- res.status(200).json(task) sends back the updated task so the client can confirm the changes.
- Save server.js.
You will not see a change yet. The next substep adds the DELETE route, then you will restart and test both together.
Add the DELETE route to remove tasks
DELETE removes a resource entirely. Instead of returning the deleted data, a successful DELETE responds with status 204, which means the server processed the request but has no content to send back.
- In server.js, add the following DELETE route directly below the PUT route you just added (and above app.listen):
// DELETE a task by ID
app.delete('/tasks/:id', (req, res) => {
const index = tasks.findIndex(t => t.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Task not found' });
}
tasks.splice(index, 1);
res.status(204).send();
});
What does this code do?
- tasks.findIndex(...) returns the position of the matching task in the array, or -1 if no task has that ID.
- tasks.splice(index, 1) removes exactly one item at that position from the array.
- res.status(204).send() sends back a 204 No Content response. This tells the client the deletion succeeded without sending a body.
- Save server.js.
Seeing a syntax error when you save?
Make sure the PUT and DELETE routes are placed between the closing }); of the POST route and the app.listen call. Each route must have its own complete set of opening and closing braces and parentheses.
Help me debug my syntax error
Test both endpoints with curl
With both routes saved, it is time to restart the server and confirm PUT and DELETE work correctly.
- Switch back to the terminal where your server is running.
- Press Ctrl+C to stop the server.
- Restart the server by running:
node server.js
You should see Task Manager API running on http://localhost:3000 in the terminal.
- Open a second terminal window for running curl commands. In VS Code, click the + icon in the terminal panel to open a new terminal tab.
- Test the PUT endpoint by running this curl command to mark task 1 as completed:
curl -X PUT http://localhost:3000/tasks/1 -H "Content-Type: application/json" -d "{\"completed\": true}"
You should see the updated task returned with completed set to true:
{"id":1,"title":"Buy groceries","completed":true}
What does this curl command do?
- -X PUT sets the HTTP method to PUT instead of the default GET.
- -H "Content-Type: application/json" tells the server the body is JSON, so express.json() can parse it.
- -d "{...}" attaches the JSON data as the request body.
- Test the DELETE endpoint by running this command to remove task 1:
curl -X DELETE http://localhost:3000/tasks/1
You should see no output. A 204 response has no body, which means silence is success here.
- Verify the deletion by fetching all tasks:
curl http://localhost:3000/tasks
You should see only tasks 2 and 3 in the response. Task 1 is gone.
Still seeing task 1 in the list?
Make sure you stopped and restarted the server after saving your code changes. The old server process does not pick up new code automatically.
If your DELETE curl ran but returned an error, check that the route uses tasks.findIndex (not tasks.find) and compares against -1.
Help me figure out why my DELETE is not working
✔️ Awesome, I've got everything!
Great. Make sure you have saved server.js with both the PUT and DELETE routes in place.
ⓧ I'd like to double check the full code
Here is the complete server.js at this point. Compare your file against it:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
let tasks = [
{ id: 1, title: 'Buy groceries', completed: false },
{ id: 2, title: 'Walk the dog', completed: true },
{ id: 3, title: 'Read a book', completed: false }
];
let nextId = 4;
// Root route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the Task Manager API' });
});
// GET all tasks
app.get('/tasks', (req, res) => {
res.status(200).json(tasks);
});
// GET a single task by ID
app.get('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.status(200).json(task);
});
// POST a new task
app.post('/tasks', (req, res) => {
const { title } = req.body;
if (!title) {
return res.status(400).json({ error: 'Title is required' });
}
const newTask = {
id: nextId++,
title: title,
completed: false
};
tasks.push(newTask);
res.status(201).json(newTask);
});
// PUT (update) a task by ID
app.put('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
if (req.body.title !== undefined) {
task.title = req.body.title;
}
if (req.body.completed !== undefined) {
task.completed = req.body.completed;
}
res.status(200).json(task);
});
// DELETE a task by ID
app.delete('/tasks/:id', (req, res) => {
const index = tasks.findIndex(t => t.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Task not found' });
}
tasks.splice(index, 1);
res.status(204).send();
});
app.listen(port, () => {
console.log(`Task Manager API running on http://localhost:${port}`);
});
All four CRUD operations are live. Your API can create, read, update, and delete tasks. Next up, you will push it even further with the Secret Mission.
Secret mission
Add Filtering and Search
Real-world APIs rarely return everything at once. Users need to filter results by status, search by keyword, or combine both. Can you upgrade your GET endpoint to handle query parameters?
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
This project runs entirely locally, so there are no ongoing costs.
Resources you used:
- The task-api project folder on your Desktop (includes server.js, package.json, and node_modules).
- The Node.js server process (running on port 3000).
- Node.js installed on your machine.
Keep everything running
No action needed. Choose this if you are still actively building or plan to extend your API soon.
- Your server stops automatically when you close the terminal window or press Ctrl+C.
- The task-api folder stays on your Desktop for future use.
- Node.js remains installed and ready for your next project.
Pause - I'll come back to this later
Shut down the running server to free up the terminal. Your project files stay intact so you can pick up where you left off.
- Switch to the terminal where your server is running and press Ctrl+C to stop it.
- Close VS Code.
- When you are ready to resume, open the task-api folder in VS Code and run node server.js in the terminal.
Delete - I don't want to use this again
Remove all project files and start fresh. Follow these steps to clean up everything.
- If your server is still running, press Ctrl+C in the terminal to stop it.
- Close VS Code.
- Delete the project folder by running this command in Command Prompt:
cd %USERPROFILE%\Desktop
rmdir /s /q task-api
- Confirm the folder is gone by running:
dir %USERPROFILE%\Desktop\task-api
You should see a message saying the system cannot find the path specified.
- To uninstall Node.js, open Settings.
- Select Apps, then Installed apps.
- Search for Node.js, click the three-dot menu, and select Uninstall.
Keep Node.js if you plan to build more
Node.js is useful for many web development projects. If you plan to continue learning JavaScript or building APIs, keep it installed.
Nice Work!
Nice Work!
You just built a REST API from scratch. Starting from an empty folder, you now have a fully functional server that handles real HTTP requests and sends back structured JSON responses.
You've learned how to:
- Built a Node.js project and Express server from an empty folder to a working REST API.
- Created a full set of CRUD endpoints (GET, POST, PUT, DELETE) with proper HTTP status codes for every response.
- Tested your API using both a browser and curl commands, handling URL parameters, request bodies, and JSON responses.
- Added filtering and search capabilities to your GET endpoint using query parameters.
Ready to quiz yourself?