How to Build Your First REST API with Node.js in 2026 (Complete Guide)
Building a REST API sounds intimidating. It's not. This step-by-step guide will take you from zero to a working API with Node.js, Express, and real endpoints in under an hour.
Every backend developer remembers their first REST API.
Mine was terrible. It worked, sort of, in the same way that a car with no brakes technically gets you moving.
This guide will help you build one that actually holds up — with proper error handling, a clean structure, and code you'll understand when you look at it a week later.
Let's go from zero to working API in about an hour.
What We're Building
A simple but complete REST API for a blog — posts you can create, read, update, and delete (CRUD). By the end, you'll have:
- Working endpoints:
GET /posts,GET /posts/:id,POST /posts,PUT /posts/:id,DELETE /posts/:id - Proper error handling
- Request validation
- Clean, reusable code structure
Prerequisites
- Node.js installed (v18+) — download from nodejs.org
- Basic JavaScript knowledge (you know what a function and object are)
- A terminal and a code editor
That's genuinely all you need.
Step 1: Set Up the Project
Open your terminal and run:
mkdir my-first-api
cd my-first-api
npm init -y
npm install express
npm install --save-dev nodemon
Now open package.json and add this to the scripts section:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
nodemon automatically restarts your server when you change a file — essential for development.
Step 2: Create the Server
Create a file called server.js in your project folder:
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware — tells Express to parse JSON request bodies
app.use(express.json());
// Basic test route
app.get('/', (req, res) => {
res.json({ message: 'API is running! 🚀' });
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Run it:
npm run dev
Open your browser and go to http://localhost:3000. You should see:
{ "message": "API is running! 🚀" }
Congratulations. You just built your first API endpoint.
Step 3: Set Up Our Data (In-Memory for Now)
In a real app you'd use a database. For this tutorial, we'll use a JavaScript array — this lets us focus on the API structure without database setup getting in the way.
Add this above your routes in server.js:
// Our "database" — an array of post objects
let posts = [
{
id: 1,
title: "My First Blog Post",
content: "This is the content of my first post.",
author: "Stackpulse",
createdAt: new Date().toISOString()
},
{
id: 2,
title: "How AI is Changing Development",
content: "AI tools are reshaping how we write code...",
author: "Stackpulse",
createdAt: new Date().toISOString()
}
];
let nextId = 3; // Simple auto-increment
Step 4: GET All Posts
// GET /posts — return all posts
app.get('/posts', (req, res) => {
res.json({
success: true,
count: posts.length,
data: posts
});
});
Test it: visit http://localhost:3000/posts. You'll see both posts returned as JSON.
Step 5: GET a Single Post
// GET /posts/:id — return one post by ID
app.get('/posts/:id', (req, res) => {
const id = parseInt(req.params.id);
const post = posts.find(p => p.id === id);
if (!post) {
return res.status(404).json({
success: false,
error: `Post with id ${id} not found`
});
}
res.json({ success: true, data: post });
});
Try http://localhost:3000/posts/1 and http://localhost:3000/posts/999. See the difference in the response.
Step 6: POST — Create a New Post
This is where it gets more interesting. To test this, you need a tool that can send POST requests — use Postman, Insomnia, or the curl command.
// POST /posts — create a new post
app.post('/posts', (req, res) => {
const { title, content, author } = req.body;
// Basic validation
if (!title || !content) {
return res.status(400).json({
success: false,
error: 'Title and content are required'
});
}
const newPost = {
id: nextId++,
title,
content,
author: author || 'Anonymous',
createdAt: new Date().toISOString()
};
posts.push(newPost);
res.status(201).json({
success: true,
data: newPost
});
});
Test with curl:
curl -X POST http://localhost:3000/posts \
-H "Content-Type: application/json" \
-d '{"title": "New Post", "content": "Hello world!"}'
Step 7: PUT — Update a Post
// PUT /posts/:id — update an existing post
app.put('/posts/:id', (req, res) => {
const id = parseInt(req.params.id);
const postIndex = posts.findIndex(p => p.id === id);
if (postIndex === -1) {
return res.status(404).json({
success: false,
error: `Post with id ${id} not found`
});
}
const { title, content, author } = req.body;
// Update only the fields that were sent
posts[postIndex] = {
...posts[postIndex],
...(title && { title }),
...(content && { content }),
...(author && { author }),
updatedAt: new Date().toISOString()
};
res.json({ success: true, data: posts[postIndex] });
});
Step 8: DELETE — Remove a Post
// DELETE /posts/:id — delete a post
app.delete('/posts/:id', (req, res) => {
const id = parseInt(req.params.id);
const postIndex = posts.findIndex(p => p.id === id);
if (postIndex === -1) {
return res.status(404).json({
success: false,
error: `Post with id ${id} not found`
});
}
posts.splice(postIndex, 1);
res.json({
success: true,
message: `Post ${id} deleted successfully`
});
});
Step 9: Handle Unknown Routes
Add this at the bottom, before app.listen:
// Handle routes that don't exist
app.use((req, res) => {
res.status(404).json({
success: false,
error: `Route ${req.method} ${req.url} not found`
});
});
Your Complete API — What You've Built
You now have a fully working REST API with:
- ✅ 5 endpoints covering all CRUD operations
- ✅ Proper HTTP status codes (200, 201, 400, 404)
- ✅ Consistent JSON response format
- ✅ Input validation
- ✅ Useful error messages
What's Next?
This API works, but it's not production-ready. Here's what to add next:
1. A real database — Replace the array with MongoDB (using Mongoose) or PostgreSQL (using Prisma). Both have great Node.js libraries.
2. Authentication — Add JWT (JSON Web Tokens) so only logged-in users can create, update, or delete posts.
3. Environment variables — Never hardcode secrets. Use dotenv to manage your PORT, database URL, and API keys.
4. Rate limiting — Protect your API from abuse with express-rate-limit.
5. Deployment — Deploy to Railway, Render, or Fly.io — all have free tiers and take under 10 minutes to set up.
The hardest part of building your first API isn't the code — it's getting over the idea that it's complicated. It's not. You just built one.
What are you going to build with it? Let me know in the comments.