How to Build a REST API with Node.js and Express: A Complete Beginner’s Tutorial
How to Build a REST API with Node.js and Express: A Hands-On Task Manager Tutorial If you are wondering how to build a REST API with Node.js, this guide will walk you through the entire process by building something real: a simple task manager API. No abstract theory, no filler. By the end, you will have a working API with routes, a database, and tested endpoints in Postman. This tutorial is written for beginners with basic JavaScript knowledge. We will use the latest stable versions of Node.js and Express available in 2026. (via https://blog.postman.com) What You Will Build A REST API for a task manager that supports the following operations: Create a new task Retrieve all tasks Retrieve a single task by ID Update an existing task Delete a task We will map these actions to standard HTTP methods: Action HTTP Method Endpoint Create task POST /api/tasks Get all tasks GET /api/tasks Get one task GET /api/tasks/:id Update task PUT /api/tasks/:id Delete task DELETE /api/tasks/:id Prerequisites Node.js 22 LTS or later installed (check with node -v) A code editor such as VS Code Postman installed for testing endpoints A free MongoDB Atlas account (or a local MongoDB instance) Step 1: Scaffold the Node.js Project Create a new folder and initialize a Node.js project: mkdir task-manager-api cd task-manager-api npm init -y Open the generated package.json and add “type”: “module” so we can use modern ES module syntax. Step 2: Install Dependencies We only need a few packages to get started: npm install express mongoose dotenv npm install –save-dev nodemon Here is what each package does: express: the web framework for routing and middleware mongoose: an ODM to interact with MongoDB dotenv: loads environment variables from a .env file nodemon: restarts the server automatically during development Add these scripts to your package.json: “scripts”: { “start”: “node server.js”, “dev”: “nodemon server.js” } Step 3: Create the Server Entry Point Create a file called server.js in the root of your project: import express from ‘express’; import mongoose from ‘mongoose’; import dotenv from ‘dotenv’; import taskRoutes from ‘./routes/tasks.js’; dotenv.config(); const app = express(); app.use(express.json()); app.use(‘/api/tasks’, taskRoutes); app.get(‘/’, (req, res) => { res.json({ message: ‘Task Manager API is running’ }); }); const PORT = process.env.PORT || 3000; mongoose.connect(process.env.MONGO_URI) .then(() => { app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); }) .catch(err => console.error(‘Database connection failed:’, err)); Step 4: Configure Environment Variables Create a .env file at the project root: PORT=3000 MONGO_URI=mongodb+srv://YOUR_USER:[email protected]/taskmanager Never commit this file. Add .env to your .gitignore. Step 5: Define the Task Model Create a folder called models and inside it a file called Task.js: import mongoose from ‘mongoose’; const taskSchema = new mongoose.Schema({ title: { type: String, required: true, trim: true }, description: { type: String, default: ” }, completed: { type: Boolean, default: false } }, { timestamps: true }); export default mongoose.model(‘Task’, taskSchema); Step 6: Build the Routes Create a folder called routes with a file called tasks.js: import express from ‘express’; import Task from ‘../models/Task.js’; const router = express.Router(); // Create a task router.post(‘/’, async (req, res) => { try { const task = await Task.create(req.body); res.status(201).json(task); } catch (err) { res.status(400).json({ error: err.message }); } }); // Get all tasks router.get(‘/’, async (req, res) => { const tasks = await Task.find().sort({ createdAt: -1 }); res.json(tasks); }); // Get one task router.get(‘/:id’, async (req, res) => { try { const task = await Task.findById(req.params.id); if (!task) return res.status(404).json({ error: ‘Task not found’ }); res.json(task); } catch (err) { res.status(400).json({ error: ‘Invalid ID’ }); } }); // Update a task router.put(‘/:id’, async (req, res) => { try { const task = await Task.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true }); if (!task) return res.status(404).json({ error: ‘Task not found’ }); res.json(task); } catch (err) { res.status(400).json({ error: err.message }); } }); // Delete a task router.delete(‘/:id’, async (req, res) => { try { const task = await Task.findByIdAndDelete(req.params.id); if (!task) return res.status(404).json({ error: ‘Task not found’ }); res.json({ message: ‘Task deleted’ }); } catch (err) { res.status(400).json({ error: ‘Invalid ID’ }); } }); export default router; Step 7: Start the Server Run the development server: npm run dev If everything is configured correctly, you should see Server running on port 3000 in your terminal. There’s a good explainer over at dev.to. Step 8: Test Your Endpoints with Postman Open Postman and try the following requests one by one. Create a task (POST) URL: http://localhost:3000/api/tasks Body (raw JSON): { “title”: “Write blog post”, “description”: “Publish the Node.js tutorial on coding4.net” } Get all tasks (GET) Send a GET request to http://localhost:3000/api/tasks and you should see an array containing the task you just created. Update a task (PUT) Copy the _id from the response and send: PUT http://localhost:3000/api/tasks/THE_ID_HERE { “completed”: true } Delete a task (DELETE) Send a DELETE request to http://localhost:3000/api/tasks/THE_ID_HERE. You should receive a confirmation message. Step 9: Add Basic Error Handling Middleware Robust APIs handle unexpected errors gracefully. Add this at the bottom of server.js, just before mongoose.connect: app.use((req, res) => { res.status(404).json({ error: ‘Route not found’ }); }); app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: ‘Internal server error’ }); }); Best Practices to Keep in Mind Use versioning in URLs, for example /api/v1/tasks, so future changes do not break clients Validate input with a library like Zod or Joi before hitting the database Return proper HTTP status codes (201 for created, 404 for not found, 400 for bad request) Never store secrets in the codebase, always use environment variables Add authentication with JWT once your API grows past a basic prototype Enable CORS if a frontend from another domain will consume the API Project Structure Recap task-manager-api/ ├── models/ │ └── Task.js ├── routes/ │ └── tasks.js ├── .env ├── .gitignore ├── package.json └── server.js Next Steps You now have a working REST API. Here are ideas to push it further: Add user authentication with JWT tokens Deploy it to Render, Railway, or Fly.io Write automated tests with Vitest or Jest Document the endpoints with Swagger
How to Build a REST API with Node.js and Express: A Complete Beginner’s Tutorial Read More »










