# CRUD API Controller

![npm](https://img.shields.io/npm/v/crud-api-express)
![downloads](https://img.shields.io/npm/dm/crud-api-express)
![license](https://img.shields.io/npm/l/crud-api-express)
![made-with-node](https://img.shields.io/badge/Made%20with-Node.js-green)
![made-with-typescript](https://img.shields.io/badge/Made%20with-TypeScript-blue)
![express](https://img.shields.io/badge/Express.js-000000?style=flat&logo=express&logoColor=white)
![MongoDB](https://img.shields.io/badge/MongoDB-47A248?style=flat&logo=mongodb&logoColor=white)



## Installation

Install the package using npm:

```bash
npm install crud-api-express
```
This project provides a flexible and reusable CRUD (Create, Read, Update, Delete) API controller for MongoDB using Express.js and Mongoose.

## Docs! ❤️  
[Doc Page Visit here](https://mukeshdev.vercel.app/crudapi)

## 📌 Table of Contents

- [Introduction](#introduction)
- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
- [Options](#options)
- [License](#license)



---

## Introduction

The `CrudController` class simplifies the creation of RESTful APIs in Node.js applications using MongoDB. It abstracts away common CRUD operations, error handling, middleware integration, and supports custom routes and aggregation pipelines.

---

## Usage

Here's a basic example of how to use in Es module `CrudController`:

```javascript
import express from 'express';
import mongoose from 'mongoose';
import CrudController from 'crud-api-express';

const Schema = mongoose.Schema;
const ExampleSchema = new Schema(
  {
    type: { type: String, default: 'Percentage', enum: ['Percentage', 'Flat'] },
    status: { type: String, default: 'Active', trim: true },
    expiry_date: { type: Date, index: true, trim: true },
  },
  { timestamps: true, versionKey: false }
);

const ExampleModel = mongoose.model('Example', ExampleSchema);

const options = {
  middleware: [
    (req, res, next) => {
      const authToken = req.headers.authorization;
      if (!authToken) {
        return res.status(401).json({ message: 'Unauthorized' });
      }
      next();
    },
    (req, res, next) => {
      console.log(`Request received at ${new Date()}`);
      next();
    },
  ],
  onSuccess: (res, method, result) => {
    console.log(`Successful ${method} operation:`, result);
    res.status(200).json({ success: true, data: result });
  },
  onError: (res, method, error) => {
    console.error(`Error in ${method} operation:`, error);
    res.status(500).json({ error: error.message });
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  aggregatePipeline: [
    { $match: { status: 'Active' } },
    { $sort: { createdAt: -1 } },
  ],
  customRoutes: [
    {
      method: 'get',
      path: '/custom-route',
      handler: (req, res) => {
        res.json({ message: 'Custom route handler executed' });
      },
    },
    {
      method: 'post',
      path: '/custom-action',
      handler: (req, res) => {
        res.json({ message: 'Custom action executed' });
      },
    },
  ],
};

const exampleController = new CrudController(ExampleModel, 'examples', options);

const mongoURI = 'mongodb://localhost:27017/mydatabase';

mongoose
  .connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log('Connected to MongoDB');

    const app = express();
    app.use(express.json());
    app.use('/api', exampleController.getRouter());

    console.log(exampleController.getRoutes());

    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
  })
  .catch((err) => {
    console.error('Error connecting to MongoDB:', err.message);
    process.exit(1);
  });
```
Here's a basic example of how to use in cjs module `CrudController`:
```javascript

const express = require('express');
const mongoose = require('mongoose');
const CrudController = require('crud-api-express');

const Schema = mongoose.Schema;
const ExampleSchema = new Schema(
  {
    type: { type: String, default: 'Percentage', enum: ['Percentage', 'Flat'] },
    status: { type: String, default: 'Active', trim: true },
    expiry_date: { type: Date, index: true, trim: true },
  },
  { timestamps: true, versionKey: false }
);

const ExampleModel = mongoose.model('Example', ExampleSchema);

const options = {
  middleware: [
    (req, res, next) => {
      const authToken = req.headers.authorization;
      if (!authToken) {
        return res.status(401).json({ message: 'Unauthorized' });
      }
      next();
    },
    (req, res, next) => {
      console.log(`Request received at ${new Date()}`);
      next();
    },
  ],
  onSuccess: (res, method, result) => {
    console.log(`Successful ${method} operation:`, result);
    res.status(200).json({ success: true, data: result });
  },
  onError: (res, method, error) => {
    console.error(`Error in ${method} operation:`, error);
    res.status(500).json({ error: error.message });
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  aggregatePipeline: [
    { $match: { status: 'Active' } },
    { $sort: { createdAt: -1 } },
  ],
  customRoutes: [
    {
      method: 'get',
      path: '/custom-route',
      handler: (req, res) => {
        res.json({ message: 'Custom route handler executed' });
      },
    },
    {
      method: 'post',
      path: '/custom-action',
      handler: (req, res) => {
        res.json({ message: 'Custom action executed' });
      },
    },
  ],
};

const exampleController = new CrudController(ExampleModel, 'examples', options);

const mongoURI = 'mongodb://localhost:27017/mydatabase';

mongoose
  .connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log('Connected to MongoDB');

    const app = express();
    app.use(express.json());
    app.use('/api', exampleController.getRouter());

    console.log(exampleController.getRoutes());

    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
  })
  .catch((err) => {
    console.error('Error connecting to MongoDB:', err.message);
    process.exit(1);
  });
```

---

## API

### `getRouter(): Router`
Returns the Express Router instance configured with CRUD routes.

```json
[
  { "method": "POST", "path": "/examples", "params": null },
  { "method": "GET", "path": "/examples", "params": ["filter", "sort", "page", "limit"] },
  { "method": "GET", "path": "/examples/:id", "params": ["id"] },
  { "method": "PUT", "path": "/examples/:id", "params": ["id"] },
  { "method": "DELETE", "path": "/examples", "params": ["filter"] },
  { "method": "DELETE", "path": "/examples/:id", "params": ["id"] },
  { "method": "GET", "path": "/examples/aggregate", "params": null },
  { "method": "GET", "path": "/examples/custom-route", "params": null },
  { "method": "POST", "path": "/examples/custom-action", "params": null }
]
```

## Options


### `CrudOptions<T>`

| Option             | Type                                                                                                      | Description                                          |
|--------------------|---------------------------------------------------------------------------------------------------------|------------------------------------------------------|
| `middleware`      | `((req: Request, res: Response, next: NextFunction) => void)[]`                                         | Array of middleware functions                       |
| `onSuccess`       | `(res: Response, method: string, result: T \| T[]) => void`                                             | Success handler function                            |
| `onError`         | `(res: Response, method: string, error: Error) => void`                                                 | Error handler function                              |
| `methods`         | `('POST' \| 'GET' \| 'PUT' \| 'DELETE')[]`                                                              | Array of HTTP methods to support                   |
| `relatedModel`    | `Model<any>`                                                                                            | Related Mongoose model for relational operations    |
| `relatedField`    | `string`                                                                                                | Field name for related models                       |
| `relatedMethods`  | `('POST' \| 'GET' \| 'PUT' \| 'DELETE')[]`                                                              | Methods to apply on related models                  |
| `aggregatePipeline` | `object[]`                                                                                            | MongoDB aggregation pipeline stages                 |
| `customRoutes`    | `{ method: 'post' \| 'get' \| 'put' \| 'delete', path: string, handler: (req: Request, res: Response) => void }[]` | Array of custom route definitions                   |

---

## 📖 Fetch All Records with Query Params (GET)

**🛠️ URL:**  
`GET http://localhost:3000/api/examples?filter={"status":"Active"}&sort={"expiry_date":1}&page=1&limit=10`

### 🔍 Query Params Explanation:
- **`filter`** → Filter results (e.g., `{ "status": "Active" }`).
- **`sort`** → Sort order (e.g., `{ "expiry_date": 1 }` for ascending).
- **`page`** → Pagination (e.g., `page=1`).
- **`limit`** → Number of results per page.


## License

This project is licensed under the **ISC License**.

## Support Me! ❤️

If you find this package useful, consider supporting me:  
[Buy Me a Coffee ☕](https://buymeacoffee.com/mrider007)

