In this tutorial, we'll walk through creating a RESTful API using Node.js and Express. We'll build a simple books API that demonstrates core concepts like routing, middleware, error handling, and basic CRUD operations.
Prerequisites
- Node.js installed on your machine
- Basic understanding of JavaScript
- A code editor
- Postman or similar tool for testing APIs
Project Setup
First, create a new directory and initialize your project:
mkdir books-api
cd books-api
npm init -y
Install the necessary dependencies:
npm install express body-parser dotenv
Project Structure
Create the following file structure:
books-api/
├── src/
│ ├── routes/
│ │ └── books.js
│ ├── middleware/
│ │ └── errorHandler.js
│ └── server.js
├── package.json
└── .env
Basic Server Setup
Create src/server.js
:
const express = require('express');
const bodyParser = require('body-parser');
const booksRouter = require('./routes/books');
const errorHandler = require('./middleware/errorHandler');
// Initialize express app
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(bodyParser.json());
// Routes
app.use('/api/books', booksRouter);
// Error handling middleware
app.use(errorHandler);
// Start server
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Creating Routes
Create src/routes/books.js
:
const express = require('express');
const router = express.Router();
// In-memory database
let books = [
{ id: 1, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
{ id: 2, title: '1984', author: 'George Orwell' }
];
// GET all books
router.get('/', (req, res) => {
res.json(books);
});
// GET book by ID
router.get('/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) return res.status(404).json({ message: 'Book not found' });
res.json(book);
});
// POST new book
router.post('/', (req, res) => {
const book = {
id: books.length + 1,
title: req.body.title,
author: req.body.author
};
books.push(book);
res.status(201).json(book);
});
// PUT update book
router.put('/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) return res.status(404).json({ message: 'Book not found' });
book.title = req.body.title || book.title;
book.author = req.body.author || book.author;
res.json(book);
});
// DELETE book
router.delete('/:id', (req, res) => {
const bookIndex = books.findIndex(b => b.id === parseInt(req.params.id));
if (bookIndex === -1) return res.status(404).json({ message: 'Book not found' });
books.splice(bookIndex, 1);
res.status(204).send();
});
module.exports = router;
Error Handling
Create src/middleware/errorHandler.js
:
function errorHandler(err, req, res, next) {
console.error(err.stack);
res.status(500).json({
message: 'Something went wrong!',
error: process.env.NODE_ENV === 'development' ? err.message : undefined
});
}
module.exports = errorHandler;
Input Validation
Let's add basic validation middleware for our POST requests:
const validateBook = (req, res, next) => {
if (!req.body.title || !req.body.author) {
return res.status(400).json({
message: 'Title and author are required'
});
}
next();
};
// Apply to POST route
router.post('/', validateBook, (req, res) => {
// ... existing post logic
});
Testing the API
Start your server:
node src/server.js
Use these curl commands to test your API:
# Get all books
curl http://localhost:3000/api/books
# Get single book
curl http://localhost:3000/api/books/1
# Create new book
curl -X POST -H "Content-Type: application/json" \
-d '{"title":"New Book","author":"John Doe"}' \
http://localhost:3000/api/books
# Update book
curl -X PUT -H "Content-Type: application/json" \
-d '{"title":"Updated Title"}' \
http://localhost:3000/api/books/1
# Delete book
curl -X DELETE http://localhost:3000/api/books/1
Next Steps
To enhance this basic API, consider:
- Adding a proper database (like MongoDB or PostgreSQL)
- Implementing authentication and authorization
- Implementing rate limiting
- Adding API documentation using Swagger
- Setting up automated testing
- Adding pagination for GET requests
- Implementing proper logging
Conclusion
You now have a working RESTful API built with Node.js and Express! This basic implementation demonstrates core concepts like routing, middleware, and error handling. While this example uses an in-memory array for storage, you can extend it by adding a database and implementing additional features as needed.
Remember to always:
- Validate input data
- Handle errors appropriately
- Follow REST conventions
- Implement proper security measures
- Document your API endpoints
Happy coding! 🚀
Related Posts
6 min read
The Model Context Protocol (MCP) has emerged as one of the most significant developments in AI technology in 2025. Launched by Anthropic in November 2024, MCP is an open standard designed to bridge AI...
5 min read
APIs (Application Programming Interfaces) are the backbone of modern digital applications. They allow different software systems to communicate, exchange data, and collaborate seamlessly. As businesse...