├── .gitignore ├── src ├── .env.sample ├── tsconfig.json ├── api │ └── example │ │ ├── example.model.ts │ │ ├── example.router.ts │ │ └── example.controller.ts ├── config │ ├── routes.ts │ └── express.ts └── server.ts ├── tsconfig.json ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | npm-debug.log 3 | .tscache 4 | *.cache 5 | dist 6 | typings 7 | bin 8 | .env 9 | .env.development -------------------------------------------------------------------------------- /src/.env.sample: -------------------------------------------------------------------------------- 1 | # 2 | # Put here all your environment variables in .env or .env.${NODE_ENV} file 3 | # and they will be loaded with your node js app 4 | # KEY=VALUE -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../dist", 5 | "baseUrl": "", 6 | "module": "commonjs" 7 | } 8 | } -------------------------------------------------------------------------------- /src/api/example/example.model.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model } from 'mongoose'; 2 | 3 | let schema: Schema = new Schema({ 4 | title: String, 5 | subtitle: String 6 | }); 7 | 8 | export default model('Example', schema); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "sourceMap": true, 5 | "declaration": false, 6 | "moduleResolution": "node", 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "target": "es5", 10 | "typeRoots": [ 11 | "node_modules/@types" 12 | ], 13 | "lib": [ 14 | "es2016", 15 | "dom" 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /src/api/example/example.router.ts: -------------------------------------------------------------------------------- 1 | import { Router, Request, Response, NextFunction } from 'express'; 2 | import ExampleController from './example.controller'; 3 | 4 | export class ExampleRouter { 5 | 6 | public router: Router 7 | 8 | 9 | /*-------- Constructor --------*/ 10 | 11 | 12 | constructor() { 13 | 14 | // 15 | // Set router 16 | this.router = Router(); 17 | this.init(); 18 | } 19 | 20 | 21 | /*-------- Methods --------*/ 22 | 23 | 24 | /** 25 | * Init all routes in this router 26 | */ 27 | init() { 28 | this.router.get('/', ExampleController.getAll); 29 | this.router.post('/', ExampleController.create); 30 | } 31 | 32 | } 33 | 34 | // 35 | // Create Router and export its configured Express.Router 36 | const exampleRoutes = new ExampleRouter(); 37 | exampleRoutes.init(); 38 | 39 | export default exampleRoutes.router; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-typescript-mongoose-starter", 3 | "version": "1.0.0", 4 | "description": "A starter for Node JS, Express, Typescript, Mongoose aplication", 5 | "main": "server.js", 6 | "scripts": { 7 | "dev": "concurrently --kill-others \"npm run watch-ts\"", 8 | "serve": "npm run build-ts & npm run start", 9 | "build-ts": "tsc -p src", 10 | "watch-ts": "tsc-watch -w -p src --onSuccess \"npm run start-dev\"", 11 | "start": "node dist/server.js", 12 | "start-dev": "NODE_ENV=development nodemon dist/server.js" 13 | }, 14 | "keywords": [ 15 | "Node", 16 | "JS", 17 | "Express", 18 | "Mongo", 19 | "Mongoose", 20 | "Typescript" 21 | ], 22 | "author": "Matheus Davidson - MTDA", 23 | "license": "ISC", 24 | "dependencies": { 25 | "body-parser": "^1.17.2", 26 | "cookie-parser": "^1.4.3", 27 | "dotenv": "^4.0.0", 28 | "ejs": "^2.5.7", 29 | "express": "^4.15.3", 30 | "mongoose": "^4.11.5", 31 | "morgan": "^1.8.2", 32 | "path": "^0.12.7" 33 | }, 34 | "devDependencies": { 35 | "@types/express": "^4.0.36", 36 | "@types/lodash": "^4.14.71", 37 | "@types/mongoose": "^4.7.19", 38 | "@types/node": "^8.0.17", 39 | "concurrently": "^3.5.0", 40 | "glob": "^7.1.2", 41 | "lodash": "^4.17.4", 42 | "nodemon": "^1.11.0", 43 | "tsc-watch": "^1.0.7", 44 | "typescript": "^2.4.2" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/api/example/example.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from 'express'; 2 | import Model from './example.model'; 3 | 4 | export default class ExampleController { 5 | 6 | /** 7 | * Get all 8 | * @param {*} req 9 | * @param {*} res 10 | * @param {*} next 11 | */ 12 | public static async getAll(req: Request, res: Response, next: NextFunction) { 13 | 14 | try { 15 | 16 | // 17 | // Get data 18 | let result = await Model.find().exec(); 19 | 20 | // 21 | // Response 22 | res.send({ 23 | message: 'it works! We got all examples', 24 | result: result 25 | }); 26 | } catch (err) { 27 | 28 | // 29 | // Error response 30 | res.send({ 31 | message: 'Could not get Examples', 32 | err: err 33 | }); 34 | } 35 | } 36 | 37 | /** 38 | * Create 39 | * @param {*} req 40 | * @param {*} res 41 | * @param {*} next 42 | */ 43 | public static async create(req: Request, res: Response, next: NextFunction) { 44 | 45 | // 46 | // Create model 47 | let model = new Model({ 48 | title: 'Test title', 49 | subtitle: 'test subtitle' 50 | }); 51 | 52 | // 53 | // Save 54 | await model.save(); 55 | 56 | res.send({ 57 | message: 'Created!', 58 | model: model 59 | }); 60 | } 61 | } -------------------------------------------------------------------------------- /src/config/routes.ts: -------------------------------------------------------------------------------- 1 | import { Router, Request, Response, NextFunction } from 'express'; 2 | import ExampleRouter from '../api/example/example.router'; 3 | 4 | export default class Routes { 5 | 6 | public router: Router; 7 | private app; 8 | 9 | 10 | /*-------- Constructor --------*/ 11 | 12 | 13 | constructor(app) { 14 | 15 | // 16 | // Set router 17 | this.router = Router(); 18 | 19 | // 20 | // Set app 21 | this.app = app; 22 | 23 | // 24 | // Set all routes 25 | this.setAllRoutes(); 26 | } 27 | 28 | 29 | /*-------- Methods --------*/ 30 | 31 | 32 | /** 33 | * Set all app routes 34 | */ 35 | setAllRoutes() { 36 | 37 | 38 | /*-------- Set all custom routes here --------*/ 39 | 40 | 41 | // 42 | // Your routes goes here 43 | this.app.use('/api/examples', ExampleRouter); 44 | 45 | 46 | /*-------- Main routes --------*/ 47 | 48 | 49 | // 50 | // Set main route for any other route found 51 | this.setMainRoute(); 52 | } 53 | 54 | /** 55 | * Set main route 56 | * this route will be used for all other routes not found before 57 | */ 58 | private setMainRoute() { 59 | 60 | // 61 | // All other routes should redirect to the index.html 62 | this.app.route('/*').get(this.index); 63 | } 64 | 65 | /** 66 | * Main route 67 | */ 68 | private index(req: Request, res: Response, next: NextFunction) { 69 | res.json({ 70 | message: 'Hello World!' 71 | }); 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import * as http from 'http'; 2 | import * as debug from 'debug'; 3 | import Express from './config/express'; 4 | 5 | 6 | /*-------- Start App --------*/ 7 | 8 | 9 | const port = normalizePort(process.env.PORT || 9000); 10 | Express.set('port', port); 11 | 12 | const server = http.createServer(Express); 13 | server.listen(port); 14 | server.on('error', onError); 15 | server.on('listening', onListening); 16 | 17 | 18 | /*-------- Methods --------*/ 19 | 20 | 21 | /** 22 | * Normalize port 23 | * @param {*} val 24 | */ 25 | function normalizePort(val: number | string): number | string | boolean { 26 | let port: number = (typeof val === 'string') ? parseInt(val, 10) : val; 27 | if (isNaN(port)) return val; 28 | else if (port >= 0) return port; 29 | else return false; 30 | } 31 | 32 | /** 33 | * On error 34 | * callback event for createServer error 35 | * @param {*} error 36 | */ 37 | function onError(error: NodeJS.ErrnoException): void { 38 | if (error.syscall !== 'listen') throw error; 39 | let bind = (typeof port === 'string') ? 'Pipe ' + port : 'Port ' + port; 40 | switch (error.code) { 41 | case 'EACCES': 42 | console.error(`${bind} requires elevated privileges`); 43 | process.exit(1); 44 | break; 45 | case 'EADDRINUSE': 46 | console.error(`${bind} is already in use`); 47 | process.exit(1); 48 | break; 49 | default: 50 | throw error; 51 | } 52 | } 53 | 54 | /** 55 | * On listening 56 | * callback event for createServer listening 57 | */ 58 | function onListening(): void { 59 | let addr = server.address(); 60 | let bind = (typeof addr === 'string') ? `pipe ${addr}` : `port ${addr.port}`; 61 | console.info(`Listening on ${bind}`); 62 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Pull Requests are welcome ;)** 2 | 3 | # Quickstart application with Express, Typescript, Mongoose 4 | This project is a starter for express, typescript and mongoose application, designed for Restful API's, but you can easily extend to make other things. 5 | 6 | I couldn't find any complete guide to archieve this, so i've looked many tutorials and posts about express with typescript and came up with seed application. 7 | 8 | ## Prerequisites 9 | 10 | 1. Latest version of Node to be installed(i recommend NVM, easier to install and possible to work with multiple node versions). 11 | 2. Install MongoDB and make sure it is running on default port 27017 (if not then please configure constants.ts and change the connection for mongoDB). 12 | 13 | ## Steps to run 14 | ```sh 15 | npm install <= install all the npm Dependencies 16 | npm run dev <= start the Nodemon and watch for changes. 17 | ``` 18 | 19 | ## Directory Structure 20 | ``` 21 | express-typescript-mongoose-starter 22 | ├── dist <= typescript will compile js to this folder 23 | ├── node_modules 24 | ├── src 25 | │ ├── .env <= for production, for other envs, use: .env.${NODE_ENV} 26 | │ ├── api 27 | │ │ ├── example <= Replace example for feature name 28 | │ │ │ ├── example.controller.ts 29 | │ │ │ ├── example.model.ts 30 | │ │ │ ├── example.router.ts 31 | │ ├── config 32 | │ │ ├── express.ts 33 | │ │ ├── routes.ts 34 | │ ├── server.ts 35 | │ ├── tsconfig.json 36 | ├── package.json 37 | ├── tsconfig.json 38 | ├── README.md 39 | ``` 40 | ## Todo 41 | - [ ] Add JWT based authentication with passport.js 42 | - [ ] Add socket.io and inject socket instace to routes and controller 43 | - [ ] Command line support to generate libraries, modules, routes and controllers 44 | 45 | ## License 46 | 47 | MIT 48 | -------------------------------------------------------------------------------- /src/config/express.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from "dotenv"; 2 | import * as bodyParser from "body-parser"; 3 | import * as cookieParser from "cookie-parser"; 4 | import * as express from "express"; 5 | import * as logger from "morgan"; 6 | import * as path from "path"; 7 | import * as mongoose from "mongoose"; 8 | import Routes from "./routes"; 9 | 10 | class Express { 11 | 12 | public app: express.Express; 13 | private envFile = 'src/.env'; 14 | 15 | 16 | /*-------- Constructor --------*/ 17 | 18 | 19 | constructor() { 20 | 21 | // 22 | // ENV 23 | this.setEnv(); 24 | 25 | // 26 | // Mongo 27 | this.connectToMongo(); 28 | 29 | // 30 | // Start App 31 | this.app = express(); 32 | 33 | // 34 | // Set view engine 35 | this.setViewEngine(); 36 | 37 | // 38 | // Middleware 39 | this.setMiddleware(); 40 | 41 | // 42 | // Set static files 43 | this.setStaticFiles(); 44 | 45 | // 46 | // Routes 47 | this.setRoutes(); 48 | } 49 | 50 | 51 | /*-------- Methods --------*/ 52 | 53 | 54 | /** 55 | * Set env 56 | * Set env from .env or .env.${NODE_ENV} file using dotenv 57 | */ 58 | private setEnv() { 59 | 60 | // 61 | // Add NODE_ENV to path if is not production 62 | if (process.env.NODE_ENV !== 'production') this.envFile += '.' + process.env.NODE_ENV; 63 | 64 | // 65 | // Set env from file 66 | dotenv.config({ path: this.envFile }); 67 | } 68 | 69 | /** 70 | * Connect to mongo 71 | */ 72 | private connectToMongo() { 73 | 74 | // 75 | // Connect to mongo using mongoose 76 | // @todo: fix "open()" DeprecationWarning warning 77 | mongoose.connect(process.env.MONGO_URI, { 78 | db: { safe: true } 79 | }); 80 | } 81 | 82 | /** 83 | * Set view engine 84 | */ 85 | private setViewEngine() { 86 | 87 | // 88 | // Configure ejs as view engine 89 | this.app.set("views", path.join(__dirname, "../../src/views")); 90 | this.app.set("view engine", "ejs"); 91 | } 92 | 93 | /** 94 | * Set middleware 95 | */ 96 | private setMiddleware() { 97 | 98 | // 99 | // Add logging 100 | this.app.use(logger("dev")); 101 | 102 | // 103 | // Add body parser 104 | this.app.use(bodyParser.json()); 105 | this.app.use(bodyParser.urlencoded({ extended: false })); 106 | 107 | // 108 | // Add cookie parser 109 | this.app.use(cookieParser()); 110 | 111 | } 112 | 113 | /** 114 | * Set static files 115 | */ 116 | private setStaticFiles() { 117 | 118 | // 119 | // Set static route for public folder 120 | this.app.use(express.static(path.join(__dirname, "../../src/public"))); 121 | } 122 | 123 | /** 124 | * Set routes 125 | */ 126 | private setRoutes() { 127 | 128 | // 129 | // Create Routes, and export its configured Express.Router 130 | new Routes(this.app); 131 | } 132 | } 133 | 134 | export default new Express().app; --------------------------------------------------------------------------------