UNPKG

node-folder-structure

Version:

Generate an Express.js app with 3-layer architecture. Quick start: npx node-folder-structure

546 lines (458 loc) 15.7 kB
const app_js = `// Main application entry point const express = require("express"); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(express.static("public")); //routes import const { userRoutes } = require('./routes/index'); //routes declaration app.use("/api/v1/user", userRoutes); module.exports = { app }` const index_js = `// Application start file const dotenv = require("dotenv"); const { app } = require("./app.js"); const { connectDB } = require("./configs/db.config.js"); dotenv.config({ path: './.env' }) const port = process.env.PORT || 8000; connectDB() .then(() => { app.listen(port, () => { console.log('⚙️ Server is running at port: ', port); }) }) .catch((err) => { console.log("MONGO db connection failed !!! ", err); })` const git_ignore = `/vendor /node_modules /public/storage Homestead.yaml Homestead.json .env .logs.log *.txt error_log .lock* *.csv .htaccess .DS_Store ` const dotenv = `# Environment variables sample PORT=8000 MONGODB_URI="mongodb://localhost:27017/" CORS_ORIGIN=* ACCESS_TOKEN_SECRET=access_token_secret ACCESS_TOKEN_EXPIRY=1d REFRESH_TOKEN_SECRET=refresh_token_secret REFRESH_TOKEN_EXPIRY=10d` const dbconfig_js = `// Database configuration const mongoose = require('mongoose'); const { dbName } = require('../constants'); exports.connectDB = async () => { try { await mongoose.connect(\`\${process.env.MONGODB_URI}/\${dbName}\`, { }); console.log('Connected to MongoDB'); } catch (error) { console.error('Error connecting to MongoDB', error); process.exit(1); } };` const dbindex_js = `// Configs index file const { connectDB } = require("./db.config"); module.exports = { connectDB };` const stripeconfig_js = `// exports.stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);` const dbname_js = `// Define your DB names exports.dbName = "your-database-name";` const constant_index_js = `// Constants index file const { dbName } = require("./dbName"); module.exports = { dbName };` const user_controller_js = `const { UserService } = require("../services"); const { asyncHandler } = require("../utils"); // Create a new user exports.createUser = asyncHandler(async (req, res) => { const userDetails = req.body; // Validation is now handled by middleware const newUser = await createUser(userDetails); if (!newUser) { throw new ApiError(500, "Something went wrong while registering the user") } return res.status(201).json( new ApiResponse(200, newUser, "User registered Successfully") ) }); // Get user by ID exports.getUserById = asyncHandler(async (req, res) => { const user = await UserService.getUser(req.params.id); return res.status(201).json( new ApiResponse(200, user, "User found Successfully") ) }); // Delete user by ID exports.deleteUserById = asyncHandler(async (req, res) => { const deletedUser = await UserService.deleteUserById(req.params.id); return res.status(201).json( new ApiResponse(200, deletedUser, "User found Successfully") ) });` const controller_index_js = `// Controllers index file const { createUser, getUserById, deleteUserById } = require("./user.controller"); module.exports = { createUser, getUserById, deleteUserById }` const cron_jobs_js = `// Cron jobs // Cron jobs are scheduled tasks that run at specific intervals in the background, commonly used for maintenance or repetitive tasks.Users can schedule commands the OS will run these commands automatically according to the given time.It is usually used for system admin jobs such as backups, logging, sending newsletters, subscription emails and more. //Creating a cron job which runs on specified time 10 am exports.scheduleCronJob = cron.schedule("00 10 * * *", function () { console.log("running a task everyday at 10 am"); });` const jobs_index = `// Jobs index file const { scheduleCronJob } = require("./cron.jobs"); module.exports = { scheduleCronJob };` const config_loaders_js = `// Config loader const _ = require('lodash'); // Example configuration validation in a loader const config = { port: process.env.PORT, databaseUrl: process.env.MONGODB_URI, }; function validateConfig(config) { if (_.isEmpty(config.port)) { throw new Error('PORT is required'); } if (!_.isString(config.databaseUrl)) { throw new Error('DATABASE_URL must be a string'); } } validateConfig(config);` const loaders_index_js = `// Loaders index file // loaders folder contains Lodash routes, configurations, and is responsible for validating configurations` const auth_middleware_js = `// Authentication middleware exports.verifyToken = asyncHandler(async (req, _, next) => { try { const token = req.cookies?.accessToken || req.header("Authorization")?.replace("Bearer ", "") if (!token) { throw new ApiError(401, "Unauthorized request") } req.user = user; next() } catch (error) { throw new ApiError(401, error?.message || "Invalid access token") } })` const multer_middleware_js = `// Multer middleware const multer = require("multer"); const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "./public/temp"); }, filename: function (req, file, cb) { cb(null, file.originalname); } }); exports.upload = multer({ storage });` const middleware_index_js = `// Middlewares index file const { verifyToken } = require("./auth.middleware"); const { upload } = require("./multer.middleware"); module.exports = { verifyToken, upload }` const model_seeders_js = `// Data seeders ` const user_model_js = `const { Schema } = require("mongoose"); const { ApiError } = require("../utils/index"); const UserModel = new Schema({ username: String, phone: String, email: String, address: String, }); exports.existingUser = async (username, email) => { await UserModel.findOne({ $or: [{ username }, { email }] }); return true; // User with email or username already exists } exports.createUser = async (userDetails) => { const newUser = await UserModel.create(userDetails); return newUser; } exports.getUserById = async (id) => { const user = await UserModel.findById(id); return user; } exports.deleteUserById = async (id) => { const deletedUser = await UserModel.findByIdAndDelete(id); return deletedUser; } ` const model_index_js = `// Models index file const { createUser, deleteUserById, getUserById } = require("./user.model"); module.exports = { createUser, getUserById, deleteUserById, }; ` const user_routes_js = `// User routes const express = require("express"); const { createUser, getUserById, deleteUserById } = require("../controllers"); const { validateUserMiddleware } = require("../validators"); const router = new express.Router(); router .route("") .post(validateUserMiddleware, createUser); router .route("/:id") .get(getUserById) .delete(deleteUserById); module.exports = router;` const routes_index_js = `// Routes index file const userRoutes = require("./user.routes"); module.exports = { userRoutes }` const user_service_js = `// User service const UserModel = require("../models/user.model"); // Service layer for user-related business logic exports.createUserService = async (userData) => { return await UserModel.createUser(userData); }; exports.getUserByIdService = async (userId) => { return await UserModel.getUserById(userId); }; exports.deleteUserByIdService = async (userId) => { return await UserModel.deleteUserById(userId); };` const services_index_js = `// Services index file const { createUserService, getUserByIdService, deleteUserByIdService } = require("./user.service"); module.exports = { createUserService, getUserByIdService, deleteUserByIdService }` const utils_apiError_js = `//ApiError class ApiError extends Error { constructor( statusCode, message = "Something went wrong", errors = [], stack = "" ) { super(message) this.statusCode = statusCode this.data = null this.message = message this.success = false; this.errors = errors if (stack) { this.stack = stack } else { Error.captureStackTrace(this, this.constructor) } } }` const utils_apiResponse_js = `//Api response class ApiResponse { constructor(statusCode, data, message = "Success") { this.statusCode = statusCode this.data = data this.message = message this.success = statusCode < 400 } }` const utils_asynchandler_js = `//Higher order functions exports.asyncHandler = (fn) => { return (req, res, next) => { Promise.resolve(fn(req, res, next)) .catch((err) => { // Set the status code to indicate an error console.error(err); res.status(500).json({ success: false, error: 'Internal server error', message: err.message }); }); }; };` const utils_generateToken_js = `//Generating tokens const jwt = require("jsonwebtoken"); const { RefreshToken } = require("../models/RefreshTokenModel"); exports.generateAccessToken = (userId) => { const token = jwt.sign({ id: userId, }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: process.env.ACCESS_TOKEN_EXPIRY }); return token; }; // Function to generate refresh token exports.generateRefreshToken = async (userId) => { try { const refreshToken = jwt.sign({ id: userId }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRY }); await RefreshToken.findOneAndDelete({ userId: userId }); await new RefreshToken({ userId, refreshToken: refreshToken }).save(); return refreshToken; } catch (error) { console.error('Error generating refresh token:', error); throw new Error('Unable to generate refresh token'); } };` const utils_index_js = `// Utils index file const { ApiError } = require("./apiError"); const { ApiResponse } = require("./apiResponse"); const { asyncHandler } = require("./asyncHandler"); const { generateAccessToken, generateRefreshToken } = require("./generateToken"); module.exports = { asyncHandler, generateAccessToken, generateRefreshToken, ApiResponse, ApiError }` const validators_user_js = `// User input validation const Ajv = require("ajv"); const { ApiError } = require("../utils"); const ajv = new Ajv(); const userSchema = { type: "object", properties: { username: { type: "string" }, phone: { type: "string", pattern: "^[0-9]{10}$" // Optional: Basic pattern for a 10-digit phone number }, email: { type: "string", format: "email" // Using the built-in email format validation }, address: { type: "string" } }, required: ["username", "email"], // Specify required fields additionalProperties: false // Disallow extra fields }; const validateUser = ajv.compile(userSchema); // Validate user data as middleware exports.validateUserMiddleware = (req, res, next) => { const valid = validateUser(req.body); if (!valid) { const errors = validateUser.errors.map(error => ({ field: error.instancePath, message: error.message, })); throw new ApiError(400, "Validation Error", errors); } next(); };` const validators_index_js = `// Validators index file const { validateUserMiddleware } = require("./user.validator"); module.exports = { validateUserMiddleware }` const package_json = `{ "name": "{{app_name}}", "version": "1.0.0", "description": "Express app with 3-layer architecture", "main": "src/index.js", "scripts": { "start": "node src/index.js", "dev": "nodemon src/index.js" }, "dependencies": { "ajv": "^8.12.0", "dotenv": "^16.0.0", "express": "^4.17.1", "mongoose": "^6.0.0", "multer": "^1.4.5-lts.1" }, "devDependencies": { "nodemon": "^2.0.22" } }` const readmeFile = ` ### Project Structure public / temp # Contains static assets like images src / # Main source code directory. | --config / # Configuration - related files like db configurations. | --constants / # Constants like db name and other fixed constraints. | --controllers / # Contains individual controllers.Handles incoming requests and generates responses. | --user.controller.js # Controls user - related requests. | --docs / # Swagger documentation for API endpoints. | --jobs / # Background jobs or scheduled tasks. | --middlewares / # Custom Express middlewares. | --loaders / # Lodash routes and configurations; also validates configurations. | --models / # Database models; ORM files for the data layer. | --seeders / # MongoDB custom seeders. | --routes / # Defines API routes. | --services / # Contains business logic and service functions | --user.service.js # User-related business logic | --utils / # Utility classes and functions. | --ApiError.js / # API error class. | --ApiResponse.js / # API response class. | --asyncHandler.js / # Higher order function to wrap asynchronous functions and handle potential errors gracefully | --generateToken.js / # Access and refresh tokens. | --validators / # Schema validation functions like Joi / AJV. | --app.js # Express app setup. | --server.js # Entry point for the application. ## Features - ✨ 3-Layer Architecture (Controller-Service-Model) - 🔒 Built-in Authentication Middleware - 🎯 Request Validation using AJV - 🚀 API Error Handling - 📝 Swagger Documentation Setup - 🔄 Background Jobs Setup - 📦 File Upload Setup with Multer - 🗃️ MongoDB Integration - 🔐 Environment Variables Setup ` module.exports = { app_js, index_js, git_ignore, dbconfig_js, dbindex_js, stripeconfig_js, dbname_js, constant_index_js, user_controller_js, controller_index_js, cron_jobs_js, jobs_index, config_loaders_js, loaders_index_js, auth_middleware_js, multer_middleware_js, middleware_index_js, model_seeders_js, user_model_js, model_index_js, user_routes_js, routes_index_js, user_service_js, services_index_js, utils_apiError_js, utils_apiResponse_js, utils_asynchandler_js, utils_generateToken_js, utils_index_js, validators_user_js, validators_index_js, dotenv, package_json, readmeFile, }