DEV Community

Cover image for Creating Generic APIs with MongoDB and Node.js
Gurkirat Singh
Gurkirat Singh

Posted on

Creating Generic APIs with MongoDB and Node.js

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
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ 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);
};
Enter fullscreen mode Exit fullscreen mode

๐Ÿงญ 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"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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)