In modern web applications, creating reusable and generic APIs can significantly speed up development and reduce redundancy. In this post, you'll learn how to build generic APIs in a Node.js backend using MongoDB and Mongoose that can adapt to different collections and schemas dynamically.
When building full-stack applications, you'll often find yourself repeating CRUD (Create, Read, Update, Delete) operations for every collection in your database. What if you could handle all of that using generic APIs?
In this post, Iโll walk you through how to build generic RESTful APIs using Node.js with MongoDB that:
- Automatically validate data using schema metadata
- Handle multiple collections dynamically
- Simplify frontend integration using a unified structure
โ๏ธ Tech Stack
- Node.js with Express
- MongoDB with Mongoose or native driver
- TypeScript (optional but recommended)
- React + MUI (for the frontend) [future post]
๐งฉ Folder Structure
/generic-api
โ
โโโ controllers/
โ โโโ generic.controller.js
โโโ routes/
โ โโโ generic.routes.js
โโโ schemas/
โ โโโ schemaConfig.js // Optional schema metadata
โโโ server.js
๐ API Endpoints
Method | Endpoint | Description |
---|---|---|
GET | /generic/:collectionName |
Fetch all documents |
GET | /generic/:collectionName/:id |
Fetch single document by ID |
POST | /generic/:collectionName |
Create a new document |
PUT | /generic/:collectionName/:id |
Update a document |
DELETE | /generic/:collectionName/:id |
Delete a document |
GET | /generic/schema/:collectionName |
Fetch schema metadata (optional) |
๐ ๏ธ Sample: Generic Controller
const { ObjectId } = require("mongodb");
const db = require("../db/mongo"); // Mongo client instance
exports.getAll = async (req, res) => {
const { collectionName } = req.params;
const collection = db.collection(collectionName);
const data = await collection.find({}).toArray();
res.json(data);
};
exports.getById = async (req, res) => {
const { collectionName, id } = req.params;
const collection = db.collection(collectionName);
const doc = await collection.findOne({ _id: new ObjectId(id) });
res.json(doc);
};
exports.create = async (req, res) => {
const { collectionName } = req.params;
const collection = db.collection(collectionName);
const result = await collection.insertOne(req.body);
res.json(result);
};
exports.update = async (req, res) => {
const { collectionName, id } = req.params;
const collection = db.collection(collectionName);
const result = await collection.updateOne(
{ _id: new ObjectId(id) },
{ $set: req.body }
);
res.json(result);
};
exports.remove = async (req, res) => {
const { collectionName, id } = req.params;
const collection = db.collection(collectionName);
const result = await collection.deleteOne({ _id: new ObjectId(id) });
res.json(result);
};
๐งญ Optional: Schema Metadata Endpoint
You can store field metadata in a collection or a separate config file. Example response for /generic/schema/users
:
{
"bsonType": "object",
"required": ["email", "name"],
"properties": {
"email": {
"bsonType": "string",
"description": "User email"
},
"name": {
"bsonType": "string",
"description": "Full name"
},
"role": {
"bsonType": "string",
"enum": ["admin", "user", "viewer"]
}
}
}
This helps the frontend dynamically render forms and data grids with appropriate validations and display names.
๐งช Testing the APIs
You can test the generic APIs using:
- Postman for manual testing
- React + MUI DataGrid to dynamically fetch and render based on schema
- Swagger/OpenAPI if you want to document it generically
โ Benefits of Generic APIs
- ๐ก Reduced Boilerplate: One controller handles all collections
- โก Rapid Development: Just create a schema and start inserting data
- ๐ Schema-Driven UI: Use schema metadata to auto-render forms and tables
- ๐ Validation Layer: Add schema validation at collection or app level
๐ง Final Thoughts
Creating generic APIs saves tons of dev effort and aligns with the DRY principle. You can always override generic behavior for edge cases or add collection-specific logic later.
This pattern works great for internal tools, admin dashboards, content platforms, or any place where data models are dynamic or frequently evolving.
Coming Next: How to build a dynamic frontend using React + MUI DataGrid that adapts to the schema from /generic/schema/:collection
.
Tags:
#nodejs
#mongodb
#api
#backend
#javascript
#fullstack
Top comments (0)