UNPKG

maggie-api

Version:

🧙‍♀️ A magical Express middleware to auto-generate CRUD APIs for Mongoose models with validation, unique keys, and middlewares.

208 lines (187 loc) 5.82 kB
import { Request, Response } from "express"; import { createDoc, updateDoc, deleteById, getAll, getById, insertMany, } from "../services"; import { Model } from "mongoose"; import { ControllerSettings } from "../utils/interface"; export const createController = ( model: Model<any>, settings: ControllerSettings ) => { const modelName = model.modelName; const { primaryKey = "" } = settings; return { addOrUpdate: async (req: Request, res: Response): Promise<any> => { try { const { _id, ...rest } = req.body; let result; // ✅ Check uniqueness for primaryKey (only if provided) if (primaryKey && rest[primaryKey]) { const existing = await model.findOne({ [primaryKey]: rest[primaryKey], }); if (_id) { // ⚠️ Prevent updating to a primary key that exists on another doc if (existing && existing._id.toString() !== _id) { return res.status(409).json({ success: false, statusCode: 409, message: `${modelName} with this ${primaryKey} already exists`, data: null, }); } } else { // ⚠️ Prevent creating if primary key already exists if (existing) { return res.status(409).json({ success: false, statusCode: 409, message: `${modelName} with this ${primaryKey} already exists`, data: null, }); } } } if (_id) { result = await updateDoc(model, { _id, ...rest }); if (!result) { return res.status(404).json({ success: false, statusCode: 404, message: `${modelName} not found`, data: null, }); } return res.status(200).json({ success: true, statusCode: 200, message: `${modelName} updated successfully`, data: result, }); } result = await createDoc(model, rest); return res.status(201).json({ success: true, statusCode: 201, message: `${modelName} created successfully`, data: result, }); } catch (error: any) { console.log(error); return res.status(500).json({ success: false, statusCode: 500, message: error.message || `Failed to process ${modelName}`, data: null, }); } }, remove: async (req: Request, res: Response): Promise<any> => { try { const result = await deleteById(model, req.params.id); return res.status(200).json({ success: true, statusCode: 200, message: `${modelName} deleted successfully`, data: result, }); } catch (error: any) { res.status(400).json({ success: false, statusCode: 400, message: error.message, data: null, }); } }, getAll: async (req: Request, res: Response): Promise<any> => { try { const result = await getAll(model, settings, req); return res.status(200).json({ success: true, statusCode: 200, message: `${modelName}s fetched successfully`, data: result, }); } catch (error: any) { return res.status(500).json({ success: false, statusCode: 500, message: error.message, data: null, }); } }, getById: async (req: Request, res: Response): Promise<any> => { try { const result = await getById(model, req.params.id, settings); if (!result) { return res.status(404).json({ success: false, statusCode: 404, message: `${modelName} not found`, data: null, }); } res.status(200).json({ success: true, statusCode: 200, message: `${modelName} fetched successfully`, data: result, }); } catch (error: any) { res.status(404).json({ success: false, statusCode: 404, message: error.message, data: null, }); } }, insertMany: async (req: Request, res: Response): Promise<any> => { try { const docs = req.body; if (!Array.isArray(docs) || docs.length === 0) { return res.status(400).json({ success: false, statusCode: 400, message: "Request body must be a non-empty array of documents", data: null, }); } // Check primary key uniqueness if (primaryKey) { const values = docs.map((doc) => doc[primaryKey]).filter(Boolean); const existing = await model.find({ [primaryKey]: { $in: values } }); if (existing.length > 0) { return res.status(400).json({ success: false, statusCode: 400, message: `Duplicate ${primaryKey} values`, error: existing.map((doc) => doc[primaryKey]), }); } } const result = await insertMany(model, docs); return res.status(201).json({ success: true, statusCode: 201, message: `${docs.length} ${modelName}(s) created successfully`, data: result, }); } catch (error: any) { return res.status(500).json({ success: false, statusCode: 500, message: error.message || `Failed to insert ${modelName}s`, data: null, }); } }, }; };