How to Build a Minimal REST API in Node.js
You need a quick backend for your frontend project. Maybe it’s a prototype, local development, or a simple production service. Setting up a Node.js REST API shouldn’t require a week of configuration.
This guide walks you through building a minimal REST API using modern Node.js and Express 5. You’ll get JSON parsing, proper error handling, and a clean structure—all in ~80 lines of code.
Key Takeaways
- Build a functional REST API with Express 5 in ~80 lines of code
- Use built-in middleware for JSON parsing without external dependencies
- Implement consistent response patterns with proper HTTP status codes
- Add centralized error handling to reduce unexpected server failures
Prerequisites
Before starting, ensure you have:
- Node.js 24 LTS or newer installed (can be downloaded from the official Node.js site)
- A code editor
- Basic JavaScript knowledge
Project Setup
Create a new directory and initialize your project:
mkdir minimal-api
cd minimal-api
npm init -y
Install Express 5:
npm install express
Open package.json and add "type": "module" to enable ESM imports. Your file should include:
{
"type": "module",
"scripts": {
"start": "node server.js"
}
}
Building Your Express 5 API
Create server.js with the following code:
import express from 'express'
const app = express()
const PORT = process.env.PORT || 3000
// Built-in JSON parsing middleware
app.use(express.json())
// In-memory data store
let items = [
{ id: 1, name: 'First item' },
{ id: 2, name: 'Second item' }
]
let nextId = 3
// GET all items
app.get('/api/items', (req, res) => {
res.json({ data: items })
})
// GET single item
app.get('/api/items/:id', (req, res) => {
const item = items.find(i => i.id === parseInt(req.params.id))
if (!item) {
return res.status(404).json({ error: 'Item not found' })
}
res.json({ data: item })
})
// POST new item
app.post('/api/items', (req, res) => {
const { name } = req.body
if (!name) {
return res.status(400).json({ error: 'Name is required' })
}
const newItem = { id: nextId++, name }
items.push(newItem)
res.status(201).json({ data: newItem })
})
// DELETE item
app.delete('/api/items/:id', (req, res) => {
const index = items.findIndex(i => i.id === parseInt(req.params.id))
if (index === -1) {
return res.status(404).json({ error: 'Item not found' })
}
items.splice(index, 1)
res.status(204).send()
})
// 404 handler for undefined routes
app.use((req, res) => {
res.status(404).json({ error: 'Route not found' })
})
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).json({ error: 'Internal server error' })
})
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`)
})
Start your server:
npm start
Understanding the JavaScript Backend API Structure
This minimal REST API Node setup covers the essentials:
JSON Parsing: Express 5 includes express.json() as built-in middleware. No external packages needed (see the Express API docs).
Consistent Responses: Every endpoint returns JSON with either a data or error property. This predictability helps frontend code handle responses uniformly.
HTTP Status Codes: The API uses appropriate codes—200 for success, 201 for created resources, 204 for successful deletions, 400 for bad requests, 404 for missing resources, and 500 for server errors.
Error Handling: The catch-all error middleware prevents unhandled route errors from crashing your server.
Discover how at OpenReplay.com.
Testing Your Endpoints
Use curl or any HTTP client:
# Get all items
curl http://localhost:3000/api/items
# Get single item
curl http://localhost:3000/api/items/1
# Create item
curl -X POST http://localhost:3000/api/items \
-H "Content-Type: application/json" \
-d '{"name": "New item"}'
# Delete item
curl -X DELETE http://localhost:3000/api/items/1
What This Doesn’t Include
This guide intentionally skips databases, authentication, and complex validation. Those concerns matter for production systems but add noise when you’re learning the fundamentals or spinning up a quick prototype.
When you’re ready to expand, consider adding:
- Input validation with a library like Zod
- Environment variables for configuration
- A database connection for persistence
Conclusion
You now have a working minimal REST API in Node.js with Express 5. The pattern here—consistent JSON responses, proper status codes, and centralized error handling—scales well as your API grows. Start with this foundation, then add complexity only when your project demands it.
FAQs
Express 5 includes native promise support for route handlers, meaning rejected promises that are returned or thrown automatically trigger error middleware. It also removes deprecated methods and improves path matching. The core API remains similar, so migration from Express 4 is straightforward for most projects.
An in-memory store keeps the example focused on API structure rather than database configuration. It works well for prototypes and learning. For production, replace the array with a database like PostgreSQL or MongoDB to persist data across server restarts.
Install the cors package with npm install cors, then import it and add app.use(cors()) before your routes. You can pass options to restrict which origins can access your API. This is necessary when your frontend runs on a different domain or port than your backend.
This structure provides a solid foundation but needs additions for production use. Add input validation, authentication, rate limiting, logging, and a proper database. The consistent response format and error handling patterns shown here scale well as you add these features.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.