{"id":16462715,"url":"https://github.com/alexstack/nodejs-express-mongodb-universal-crud-api","last_synced_at":"2025-02-27T08:29:40.069Z","repository":{"id":57409918,"uuid":"307931057","full_name":"AlexStack/NodeJs-Express-MongoDB-Universal-CRUD-API","owner":"AlexStack","description":"NodeJs-Express-MongoDB-Universal-CRUD-API(Universal MEAN API) for dynamic MongoDB tables, no need to repeat the CRUD API code for every table.  Focus run it in a serverless environment. ","archived":false,"fork":false,"pushed_at":"2021-12-07T18:03:30.000Z","size":985,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-24T15:43:47.234Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://reactadmindemo.now.sh","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AlexStack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-28T06:54:06.000Z","updated_at":"2021-12-07T18:03:33.000Z","dependencies_parsed_at":"2022-08-24T18:51:24.915Z","dependency_job_id":null,"html_url":"https://github.com/AlexStack/NodeJs-Express-MongoDB-Universal-CRUD-API","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexStack%2FNodeJs-Express-MongoDB-Universal-CRUD-API","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexStack%2FNodeJs-Express-MongoDB-Universal-CRUD-API/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexStack%2FNodeJs-Express-MongoDB-Universal-CRUD-API/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexStack%2FNodeJs-Express-MongoDB-Universal-CRUD-API/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AlexStack","download_url":"https://codeload.github.com/AlexStack/NodeJs-Express-MongoDB-Universal-CRUD-API/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240995365,"owners_count":19890723,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T11:12:08.166Z","updated_at":"2025-02-27T08:29:40.030Z","avatar_url":"https://github.com/AlexStack.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Serverless Universal MEAN API\n\n- This package allow you to set up a backend API using node.js \u0026 mongodb in 2 minutes\n- An Universal RESTful CRUD API for dynamic multiple collections of mongodb (database tables) with Node.js and Express.js, we DO NOT need to code the CRUD route/controller for each collection/table anymore.\n- Designed to run on Serverless environment, such as AWS Lambda, Azure, Google, NetLify, Vercel\n- Universal MEAN API stands for MongoDB(M) + Express.js(E) + Universal CRUD API(A) + Node.js(N)\n- All schemas and api routes can define in ONE file: api.config.js (No need to create mongodb collection beforehand)\n- Come with a react-admin demo\n- Support field search(=, %like%, full-text) and some json-sever standard parameters: \\_sort, \\_order, \\_start, \\_end, \\_limit, \\_like, \\_gte, \\_lte, id=1,2,3,4,5\n\n## How to install\n\n- npm install universal-mean-api\n\n## AWS Lambda example\n\n- Demo: https://k2qt3w8a07.execute-api.ap-southeast-2.amazonaws.com/dev/api/posts\n- [AWS Lambda Code example is here](https://github.com/AlexStack/NodeJs-Express-MongoDB-Universal-CRUD-API/tree/master/example/awsLambda)\n- Change the serverless.yml before deploy\n- You need remove - \"node_modules/\\*\\*\" from the exclude in serverless.yml if you want to deploy node_modules together\n- You can upload a nodejs layer instead of deploy node_modules every time\n- create_lambda_layer.sh can be used to create a node_modules layer\n- Change config/meanapi.config.js\n- Add DB environment via aws lambda UI\n- Done\n\n## Serverless function example for NetLify\n\n- Demo: https://meanapi.netlify.app/\n- [NetLify serverless function Code example is here](https://github.com/AlexStack/NodeJs-Express-MongoDB-Universal-CRUD-API/tree/master/example/netlify)\n- Change netlify/functions/meanapi/meanapi.config.js\n- Change the netlify.toml if need\n- According to some research, the Netlify Functions cannot access the Env Variables from netlify.toml. So, Please set up below environment variables from the Netlify website UI manually:\n  DB = \"YOUR-MONGODB-URI\"\n  API_BASE = \".netlify/functions/.netlify/functions/meanapi/\"\n  API_CONFIG_FILE = \"/var/task/src/functions/meanapi/meanapi.config.js\"\n\n## Serverless function example for Vercel\n\n- Demo: https://meanapi.vercel.app/\n- [Vercel function Code example is here](https://github.com/AlexStack/NodeJs-Express-MongoDB-Universal-CRUD-API/tree/master/example/vercel)\n- Change config/meanapi.config.js\n- Change the vercel.json if need\n\n## How to use locally\n\n- You only need create 2 js files after install: server.js \u0026 meanapi.config.js\n- Then run command: node server.js to see the result\n- Done!\n- The file structure example:\n\n```JavaScript\n  /node_modules\n  /package-lock.json\n  /server.js\n  /meanapi.config.js or /config/meanapi.config.js or /config/api.config.js\n```\n\n- Basic example code for server.js:\n\n```JavaScript\nconst { app, serverless, API_CONFIG } = require(\"universal-mean-api\");\nif (API_CONFIG.IS_SERVERLESS) {\n    module.exports.lambdaHandler = serverless(app); // handler for serverless function\n} else {\n    app.listen(app.get('config').PORT, () =\u003e {\n        console.log(`API is running on port ${API_CONFIG.PORT}.`);\n    });\n}\n```\n\n- Basic example of meanapi.config.js (API variables \u0026 MongoDB schemas \u0026 routes)\n\n```JavaScript\nmodule.exports.DB = process.env.DB || 'please-set-database-connect-uri-first';\nmodule.exports.API_BASE = process.env.API_BASE || 'api/';\nmodule.exports.PORT = process.env.PORT || '8080';\nmodule.exports.CORS_ORIGIN = process.env.CORS_ORIGIN || [/localhost/, /\\.test$/];\nmodule.exports.IS_SERVERLESS = !!(process.env.LAMBDA_TASK_ROOT || process.env.AWS_LAMBDA_FUNCTION_NAME);\n\nmodule.exports.API_SCHEMAS = [\n    {\n        \"apiRoute\": \"test1\",\n        \"collectionName\": \"test1\",\n        \"schema\": {\n            name: String,\n            description: String,\n            type: String,\n            gender: String,\n            dob: Date,\n            userId: { type: Number, required: [true, 'userId is required.'] }\n        },\n        \"mongooseOption\": { timestamps: true, strict: false },\n        \"searchFields\": [\"name\", \"description\", \"type\"],\n    },\n    {\n        \"apiRoute\": \"test2\",\n        \"collectionName\": \"test2\",\n        \"schema\": {\n            title: {\n                type: String,\n                required: [true, 'Title is required.']\n            },\n            description: String,\n            age: {\n                type: Number,\n                min: [18, 'Too young'],\n                max: 80\n            }\n        },\n        \"mongooseOption\": { timestamps: true, strict: true },\n        \"searchFields\": [\"description\", \"title\"],\n    },\n    {\n        \"apiRoute\": \"test3\",\n        \"collectionName\": \"test3\",\n        \"schema\": {\n            address: String,\n            description: String\n        },\n        \"mongooseOption\": { timestamps: false, strict: false },\n        \"searchFields\": [\"address\"],\n    }\n];\n\n\n```\n\n## How to access the RESTful API\n\n- Based on above example server.js \u0026 meanapi.config.js files, we can access the localhost:8080 by run command node server.js or nodemon server.js\n- RESTful API endpoint for collection \u003c tablename \u003e: http://localhost:8080/api/\u003c tablename \u003e\n- RESTful API endpoint for collection test1: http://localhost:8080/api/test1\n- RESTful API endpoint for collection test2: http://localhost:8080/api/test2\n- RESTful API endpoint for collection test3: http://localhost:8080/api/test3\n- RESTful API endpoint support GET/POST/PUT/DELETE and fields search\n\n## RESTful API CRUD routes example\n\n```JavaScript\nGET http://localhost:8080/api/test1\nGET http://localhost:8080/api/test1/\u003cid\u003e\nPOST http://localhost:8080/api/test1\nPUT http://localhost:8080/api/test1/\u003cid\u003e\nPATCH http://localhost:8080/api/test1/\u003cid\u003e\nDELETE http://localhost:8080/api/test1/\u003cid\u003e\n```\n\n## Field search route examples\n\n- GET /api/test1?name_like=mean\u0026description_like=api\n- GET /api/test1?age_lgt=18\u0026\\_limit=20\n- GET /api/test1?id=1\u0026id=2\u0026id=3\n- GET /api/test1?id=1,2,3,4 or ?\\_id=1,2,3,4\n\n## Sort \u0026 order by examples\n\n- GET /api/test1?\\_sort=age\u0026\\_order=dasc\u0026\\_start=10\u0026\\_end=20\u0026name_like=api\n\n## Get data from relationship collections or tables\n\n- To include children resources, add \\_embed\n- To include parent resource, add \\_expand\n- e.g. /pets/5fcd8f4a3b755f0008556057?\\_expand=user,file|mainImageId\u0026\\_embed=pets,stories\n- \\_expand=user,file|mainImageId means get parent data from parent table users and files. it will use userId and fileId as the foreign key by default unless you set it by table|foreignKey. e.g. file|mainImageId, file is the singular table name and mainImageId is the foreignKey\n- Only support the detail route at this moment, will add to the list route\n\n## User auth check system (check if the user is the owner or admin via JWT access token)\n\n- ENABLE_AUTH: enable user auth check system or not\n- ENABLE_AUTH=true, all edit/delete/add(update/destroy/create) requests has to be the owner or admin\n- ENABLE_AUTH=false, test \u0026 debug mode, everyone can view/edit/delete\n- e.g. module.exports.ENABLE_AUTH = true;\n\n- USER_ROUTE: user table api endpoint route\n- e.g. module.exports.USER_ROUTE = 'users';\n\n- FIELD_USER_ID: the foreign key id in other tables to user id\n- e.g. module.exports.FIELD_USER_ID = 'userId';\n\n- by default all GET request no need check user auth\n- if we want enable auth check for a table/collection list/show GET request\n- set readRules for each table/collection like below\n- \"readRules\": { \"checkAuth\": true, \"checkOwner\": true }\n- e.g. CRUD for orders table/collection, need to login first to do anything, only the owner itself can view/add/edit/delete his/her orders\n\n- Who is admin? Set role field in users table to admin or xxxAdmin (any role value contains string \"admin\" will consider is an admin role)\n- e.g. role=webAdmin, role=admin, role=SuperAdmin, role=Dashboard Admin\n- admin has all permissions for now\n\n## How to set admin only add/edit/delete permission\n\n- add/edit/delete request allow owner itself by default\n- if you want set admin only for some system tables, e.g. settings, categories\n- Add \"writeRules\": { \"checkAdmin\": true } to the schema settings in api.config.js\n\n## How to allow create item anonymous\n\n- Sometimes we want allow create item anonymous. e.g. a contact us form\n- Add \"writeRules\": { \"ignoreCreateAuth\": true } to the schema settings in api.config.js\n- NOTE: It still requires login if there is a \\_POST[userId] parameter for security reason\n- edit/delete still requires owner or admin\n\n## How to set up a private item\n\n- Sometimes we want create item privately. e.g. something is public while others is private, or private message \u0026 public comment\n- Add \"isPublic: Boolean\" to the schema settings in api.config.js\n- Set FIELD_PUBLIC = 'isPublic' and FIELD_TARGET_USER_ID = 'ownerId' to fit your needs\n- The API will check if there is a isPublic field in the schema first, then check the current user or target user is match or not\n- Example 1: a story set isPublic=false, means it is private. only the owner itself can view/edit it. Other users can not event list or view it.\n- Example 2: a private message sent to userA from userB, only those two users both can view the message, however, only userB can edit/delete the message.\n\n## How to update some fields anonymous\n\n- selfUpdateFields only allow 1 increase/decrease self update unless use is admin\n- \"writeRules\": { \"selfUpdateFields\": [\"viewNum\", \"likeNum\", \"commentNum\"] }\n- Note: selfUpdateFields will exclude from owner itself update\n\n## return data - all JSON format\n\n- add or update request, returns the NEW item object if success\n- list request, returns an array contains all item objects\n- show/detail request, returns the item object if success\n- delete request, the http status returns 200 if success\n\n## Debug locally\n\n- npm install universal-mean-api\n- npx nodemon server.js (or nodemon server.js)\n- cd reactAdmin\n- npm start\n\n## Example of adding a custom route to server.js?\n\n- Below example is add a custom /api/sitemap route to server.js\n- It read data from collection posts and output a text format sitemap for google\n\n```javascript\nconst { app, API_CONFIG, db } = require(\"universal-mean-api\");\n\n// custom route start\napp.get(\"/\" + API_CONFIG.API_BASE + \"sitemap\", async (req, res, next) =\u003e {\n  const urls = await db[\"posts\"]\n    .find()\n    .sort({ _id: -1 })\n    .limit(100)\n    .then((data) =\u003e {\n      let urls = [];\n      data.map((item) =\u003e {\n        urls.push(\"https://your-website.com/posts/\" + item.id);\n      });\n      return urls;\n    });\n  res.send(urls.join(\"\\n\"));\n});\n// custom route end\n\napp.set(\"test1111\", \"/\" + API_CONFIG.API_BASE + \"sitemap\");\n\napp.listen(API_CONFIG.PORT, () =\u003e {\n  console.log(\n    `Server is running on port ${API_CONFIG.PORT}. process.cwd()=` +\n      process.cwd()\n  );\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexstack%2Fnodejs-express-mongodb-universal-crud-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexstack%2Fnodejs-express-mongodb-universal-crud-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexstack%2Fnodejs-express-mongodb-universal-crud-api/lists"}