A production-ready public REST API for managing 10,000+ product records, built with Node.js, Express.js, and MongoDB.
- Full CRUD operations for products
- Pagination (default 50 per page, max 100)
- Full-text search by name
- Filter by category and price range
- Sorting by price (asc/desc) and date (newest/oldest)
- MongoDB indexes for high-performance queries
- CORS enabled (public access)
- Input validation and structured error responses
product-api/
├── config/
│ └── db.js # MongoDB connection
├── controllers/
│ └── productController.js # Request handlers
├── models/
│ └── Product.js # Mongoose schema & indexes
├── routes/
│ └── productRoutes.js # Express routes
├── scripts/
│ └── seed.js # Seed 10,000 fake products
├── .env.example # Environment variable template
├── .gitignore
├── package.json
├── postman_collection.json # Postman collection
├── README.md
└── server.js # Entry point
- Node.js v18+
- MongoDB (local or MongoDB Atlas)
git clone <repository-url>
cd product-api
npm installCopy the example env file and update values:
cp .env.example .envEdit .env:
PORT=5000
MONGO_URI=mongodb://localhost:27017/productdbFor MongoDB Atlas, use your connection string:
MONGO_URI=mongodb+srv://<username>:<password>@cluster0.xxxxx.mongodb.net/productdb?retryWrites=true&w=majority# Development (with auto-reload)
npm run dev
# Production
npm startThe API will be available at http://localhost:5000.
Insert 10,000 fake product records:
npm run seedhttp://localhost:5000
Get all products with pagination, filtering, and sorting.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number |
| limit | number | 50 | Items per page (max 100) |
| search | string | - | Full-text search by product name |
| category | string | - | Filter by category (case-insensitive) |
| minPrice | number | - | Minimum price filter |
| maxPrice | number | - | Maximum price filter |
| sort | string | newest | Sort order: price_asc, price_desc, newest, oldest |
Example requests:
# Get first page with 10 products
GET /api/products?page=1&limit=10
# Search for headphones
GET /api/products?search=headphones
# Filter by category
GET /api/products?category=Electronics
# Filter by price range, sorted by price ascending
GET /api/products?minPrice=10&maxPrice=100&sort=price_asc
# Combined: search + category + sort
GET /api/products?search=speaker&category=Electronics&sort=price_desc&limit=20Example response:
{
"success": true,
"total": 10000,
"page": 1,
"pages": 200,
"limit": 50,
"data": [
{
"_id": "665abc123def456789012345",
"name": "Premium Headphones 1",
"description": "High quality premium headphones - product #1.",
"price": 49.99,
"category": "Electronics",
"stock": 120,
"createdAt": "2024-06-01T12:00:00.000Z",
"updatedAt": "2024-06-01T12:00:00.000Z"
}
]
}Get a single product by its ID.
GET /api/products/665abc123def456789012345Response (200):
{
"success": true,
"data": {
"_id": "665abc123def456789012345",
"name": "Premium Headphones 1",
"price": 49.99,
"category": "Electronics",
"stock": 120,
"createdAt": "2024-06-01T12:00:00.000Z",
"updatedAt": "2024-06-01T12:00:00.000Z"
}
}Response (404):
{
"success": false,
"message": "Product not found"
}Create a new product.
Required fields: name, price
POST /api/products
Content-Type: application/json
{
"name": "Smart Wireless Speaker",
"description": "Crystal clear audio with 360-degree sound",
"price": 79.99,
"category": "Electronics",
"stock": 50
}Response (201):
{
"success": true,
"data": {
"_id": "665abc123def456789012345",
"name": "Smart Wireless Speaker",
"price": 79.99,
"category": "Electronics",
"stock": 50,
"createdAt": "2024-06-01T12:00:00.000Z",
"updatedAt": "2024-06-01T12:00:00.000Z"
}
}Update an existing product. Only include fields you want to change.
PUT /api/products/665abc123def456789012345
Content-Type: application/json
{
"price": 89.99,
"stock": 75
}Response (200):
{
"success": true,
"data": {
"_id": "665abc123def456789012345",
"name": "Smart Wireless Speaker",
"price": 89.99,
"stock": 75,
"updatedAt": "2024-06-01T13:00:00.000Z"
}
}Delete a product by ID.
DELETE /api/products/665abc123def456789012345Response (200):
{
"success": true,
"message": "Product deleted successfully"
}| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Resource created |
| 400 | Bad request / validation error |
| 404 | Resource not found |
| 500 | Internal server error |
All error responses follow this format:
{
"success": false,
"message": "Error description"
}- Open Postman
- Click Import (top left)
- Select
postman_collection.jsonfrom this repository - The collection "Product API" will appear in your collections list
- Set the
base_urlvariable to your API URL (default:http://localhost:5000) - Start making requests!
- Push your code to GitHub
- Go to render.com and create a new Web Service
- Connect your GitHub repository
- Configure:
- Build Command:
npm install - Start Command:
npm start
- Build Command:
- Add environment variables in the Render dashboard:
MONGO_URI— your MongoDB Atlas connection stringPORT— leave blank (Render sets this automatically)
- Click Deploy
- Push your code to GitHub
- Go to railway.app and create a new project
- Click Deploy from GitHub repo
- Add environment variables in Railway settings:
MONGO_URI— your MongoDB Atlas connection string
- Railway auto-detects Node.js and runs
npm start
- Create a free cluster at mongodb.com/atlas
- Whitelist
0.0.0.0/0(allow all IPs) in Network Access - Create a database user
- Get your connection string and set it as
MONGO_URI
- MongoDB indexes on
name(text),category,price, andcreatedAtensure fast queries on 10,000+ records .lean()is used on read queries to return plain JS objects (faster than Mongoose documents)Promise.allis used to run data fetch and count queries in parallel- Batch inserts of 500 records at a time in the seed script