maggie-api
v1.1.3
Published
π§ββοΈ A magical Express middleware to auto-generate CRUD APIs for Mongoose models with validation, unique keys, and middlewares.
Maintainers
Keywords
Readme
π§ββοΈ maggie-api
Auto-generate full-featured CRUD APIs for your Mongoose models in Express with one powerful config.
Supports:
- β Joi Validation
- β Custom Middlewares
- β Unique Primary Key Constraints
- β Add/Update Merged API
- β Consistent JSON Responses
- β Field Selection & Population
- β Bulk Insert Support
- β Dynamic Search (with keyword, fields, and case sensitivity support)
- β Pagination Support (limit & page query)
- β Sorting Support (ascending, descending, multi-field)
- β
Filtering Support (with allowed fields and advanced operators like
$gte,$in) - β Auto Pluralized Response Keys
- β Full CRUD API Auto-generation
π¦ Installation
npm install maggie-api
# Peer dependencies
npm install express mongoose joiπ Quick Start
import express from "express";
import { createMaggie } from "maggie-api";
import Models from "./models";
import Joi from "joi";
const app = express();
app.use(express.json());
const UserValidationSchema = Joi.object({
_id: Joi.string(),
firstName: Joi.string().required(),
lastName: Joi.string().required(),
email: Joi.string().email().required(),
});
const apiRouter = createMaggie({
prefix: "/api/v1",
models: [
{
model: ProductModel,
path: "product",
validationSchema: productValidationSchema,
settings: {
get: {
// β
Only these fields will be returned in GET /product
keys: ["_id", "title", "price", "description", "subCategory"],
// π Search by title or description using `?search=some+word`
search: {
disabled: false,
allowedFields: ["title", "description"],
},
// π§Ή Allow filtering via `?filter[price][gte]=100` or `filter[title]=Shoes`
filter: {
allowedFields: ["price", "title", "subCategory"],
},
// π Populate referenced subCategory and its category
populate: [
{
path: "subCategory",
select: ["_id", "title"],
populate: [{ path: "category", select: ["_id", "title"] }],
},
],
},
getById: {
// β
Only these fields will be returned in GET /product/:id
keys: ["_id", "title", "description", "price", "subCategory"],
// π Nested populate same as `get`
populate: [
{
path: "subCategory",
select: ["_id", "title"],
populate: [{ path: "category", select: ["_id", "title"] }],
},
],
},
},
},
],
});
app.use(apiRouter);
app.listen(3000, () => {
console.log("Server running at http://localhost:3000");
});π Features
1. Add or Update API (POST /:model)
- Merges create and update logic into a single endpoint.
- If the request body contains
_id, it triggers an update; otherwise, a new record is created. - Automatically checks
primaryKeyuniqueness during creation. - During update, it ignores the current document when checking for duplicates.
2. Joi Validation
- Supports request body validation using Joi schemas for
POSToperations. - Only one validation error message is returned per request to enhance clarity.
- Validation schemas are customizable per model.
3. Primary Key Uniqueness
- Define a
primaryKey(e.g.email,username) to enforce uniqueness on creation. - If a duplicate is found, the API returns a descriptive error.
4. Custom Middlewares
- Use the
middleWaresarray to inject custom Express middlewares into thePOSTroute. - Enables features like authentication, authorization, logging, etc.
5. Field Filtering (Deprecated)
- β οΈ
getKeysandgetByIdKeysare deprecated. - Use
settings.get.keysto select fields inGET /:model. - Use
settings.getById.keysto select fields inGET /:model/:id. - This improves flexibility and aligns with modern structured configurations.
6. CRUD Endpoints (Auto-generated)
| Method | Endpoint | Description |
| -------- | ------------------- | --------------------- |
| POST | /api/v1/user | Create or Update User |
| POST | /api/v1/user/bulk | Bulk Insert Users |
| GET | /api/v1/user | Fetch all Users |
| GET | /api/v1/user/:id | Fetch User by ID |
| DELETE | /api/v1/user/:id | Delete User by ID |
7. Population Support
- Use
settings.get.populateandsettings.getById.populateto populate referenced fields. - Each populate config accepts a
pathand optionalselectarray for nested or targeted population.
settings: {
get: {
populate: [
{ path: "department", select: ["_id", "title"] }
]
},
getById: {
populate: [
{
path: "department",
select: ["_id", "title"] ,
populate: [
{
path: "item",
selected: ["_id", "title"]
}
],
}
]
}
}8. Search Support
- β
Use
settings.get.searchto enable keyword-based searching on specific fields. - π Accepts query parameters like
search,searchFields, andcaseSensitive. - π§© Only fields defined in
allowedFieldswill be considered for searching. - π If
disabled: true, searching will be turned off for that model. - π Falls back to all allowed fields if
searchFieldsparam is not provided.
Example Setting:
settings: {
get: {
search: {
disabled: false,
allowedFields: ["title", "description", "email"]
}
}
}Sample Request:
GET /api/v1/user?search=mascara&searchFields=title,description&caseSensitive=falseBehavior:
- Builds a
$orregex search query for all specified fields. - If no valid fields are provided or allowed β search is skipped.
9. Sorting, Pagination & Filtering (Built-in)
Sorting, pagination, and filtering are first-class citizens in maggie-api, available out of the box for all models.
π Sorting
Pass a
sortquery param to define sort order:?sort=-createdAt,nameUse a hyphen (
-) prefix for descending order.Multiple fields can be sorted in sequence.
Sorting is always enabled β no extra config needed.
π Pagination
Supports standard pagination via
limitandpagequery parameters:?limit=10&page=2Only applied when both parameters are valid positive integers.
Automatically returns metadata:
{ "users": [...], "pagination": { "total": 100, "page": 2, "limit": 10, "totalPages": 10 } }If not provided, returns the full result set without pagination.
π Example:
GET /api/v1/product?filter[price][gte]=500&sort=-createdAt&limit=10&page=1β οΈ Sorting and pagination are always enabled by default. Filtering requires configuring
allowedFieldsto avoid accidental or insecure filtering.
This makes it easy to power powerful, customizable tables and dashboards with minimal backend configuration.
10. Filter Support
maggie-api allows powerful and flexible filtering on API endpoints using structured query parameters.
π§ Key Features:
- Declarative control over filterable fields via
settings.get.filter.allowedFields - Automatically transforms nested filters into MongoDB-compatible queries
- Supports value types: primitives, arrays, and range operators
π€ Supported Operators:
| Operator | Usage | Translates To |
| -------- | ------------------------ | -------------------------- |
| eq | filter[status]=active | { status: "active" } |
| in | filter[tags][]=a&[]=b | { tags: { $in: [...] } } |
| gte | filter[price][gte]=100 | { price: { $gte: 100 } } |
| lte | filter[price][lte]=500 | { price: { $lte: 500 } } |
| gt, lt | Similar usage | $gt, $lt |
π‘ Behavior:
- If a filter field is not included in
allowedFields, it will be silently ignored. - Case-sensitive by default (you may use search for regex-based keyword lookups).
- Compatible with MongoDB query syntax for advanced filtering.
π§ͺ Example Request:
GET /api/v1/user?filter[role]=admin&filter[age][gte]=18β οΈ Important:
- Always whitelist filterable fields to avoid misuse or performance hits
- For flexible keyword matching across multiple fields, use the
searchconfig instead
This filtering system is perfect for admin dashboards, search filters, and dynamic list views.
π‘ Sample cURL Commands
β Add a User
curl -X POST http://localhost:3000/api/v1/user \
-H "Content-Type: application/json" \
-d '{"firstName":"Alice","lastName":"Doe","email":"[email protected]"}'βοΈ Update a User
curl -X POST http://localhost:3000/api/v1/user \
-H "Content-Type: application/json" \
-d '{"_id":"665c8d1234567890","firstName":"Alicia","email":"[email protected]"}'π Get All Users
curl http://localhost:3000/api/v1/userπ Get User by ID
curl http://localhost:3000/api/v1/user/665c8d1234567890β Delete User by ID
curl -X DELETE http://localhost:3000/api/v1/user/665c8d1234567890π Bulk Insert Users
curl -X POST http://localhost:3000/api/v1/user/bulk \
-H "Content-Type: application/json" \
-d '[
{"firstName":"Bob","lastName":"Smith","email":"[email protected]"},
{"firstName":"Carol","lastName":"Jones","email":"[email protected]"}
]'β Standard JSON Response Format
maggie-api follows a consistent, frontend-friendly response structure for all CRUD operations.
π’ On Success
Create:
{
"success": true,
"statusCode": 201,
"message": "User created successfully",
"data": {
"_id": "665c8d1234567890",
"firstName": "Alice",
"email": "[email protected]"
}
}Update:
{
"success": true,
"statusCode": 200,
"message": "User updated successfully",
"data": {
"_id": "665c8d1234567890",
"firstName": "Alicia"
}
}Get All (with optional pagination):
{
"success": true,
"statusCode": 200,
"message": "Users fetched successfully",
"data": {
"users": [...],
"pagination": {
"total": 100,
"page": 2,
"limit": 10,
"totalPages": 10
}
}
}Get by ID:
{
"success": true,
"statusCode": 200,
"message": "User fetched successfully",
"data": {
"_id": "665c8d1234567890",
"firstName": "Alice"
}
}Delete:
{
"success": true,
"statusCode": 200,
"message": "User deleted successfully",
"data": {
"_id": "665c8d1234567890"
}
}Bulk Insert:
{
"success": true,
"statusCode": 201,
"message": "3 Users created successfully",
"data": [{}, {}, {}]
}π΄ On Errors
Validation Error:
{
"success": false,
"statusCode": 400,
"message": "Validation error",
"error": "\"email\" is required"
}Duplicate Primary Key (Create or Bulk Insert):
{
"success": false,
"statusCode": 409,
"message": "User with this email already exists",
"data": null
}Document Not Found (Update or GetById):
{
"success": false,
"statusCode": 404,
"message": "User not found",
"data": null
}Invalid Request Format (e.g. Bulk Insert with non-array):
{
"success": false,
"statusCode": 400,
"message": "Request body must be a non-empty array of documents",
"data": null
}Server Error:
{
"success": false,
"statusCode": 500,
"message": "Failed to process User",
"data": null
}π Example Project Structure
your-app/
βββ models/
β βββ User.ts
βββ routes/
β βββ index.ts
βββ utils/
β βββ validateBody.ts
βββ app.ts
βββ ...π Contributing
Want to contribute or enhance? PRs are welcome!
- Add new features like PATCH support, role-based auth, etc.
- Improve test coverage
- Bug fixes
π’ Final Words
Save hours of boilerplate setup. Focus on your app logic.
Let maggie-api handle the API plumbing. π
