├── .env.example ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── package-lock.json ├── package.json ├── src ├── app.ts ├── index.ts ├── middleware │ ├── authenticated.middleware.ts │ ├── error.middleware.ts │ └── validation.middleware.ts ├── resources │ ├── post │ │ ├── post.controller.ts │ │ ├── post.interface.ts │ │ ├── post.model.ts │ │ ├── post.service.ts │ │ └── post.validation.ts │ └── user │ │ ├── user.controller.ts │ │ ├── user.interface.ts │ │ ├── user.model.ts │ │ ├── user.service.ts │ │ └── user.validation.ts └── utils │ ├── definitions │ └── custom.d.ts │ ├── exceptions │ └── http.exception.ts │ ├── interfaces │ ├── controller.interface.ts │ └── token.interface.ts │ ├── token.ts │ └── validateEnv.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | PORT=3000 3 | MONGO_PATH= 4 | MONGO_USER= 5 | MONGO_PASSWORD= 6 | JWT_SECRET= -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "plugin:@typescript-eslint/recommended", 5 | "prettier/@typescript-eslint", 6 | "plugin:prettier/recommended", 7 | ], 8 | parserOptions: { 9 | ecmaVersion: 2018, 10 | sourceType: "module", 11 | }, 12 | rules: {}, 13 | }; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .env -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 4, 3 | singleQuote: true, 4 | semi: true, 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-api-from-scratch", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node dist/index.js", 9 | "dev": "tsc-watch --onSuccess \"node ./dist/index.js\"", 10 | "build": "tsc", 11 | "postinstall": "npm run build" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "@types/bcrypt": "^5.0.0", 18 | "@types/compression": "^1.7.2", 19 | "@types/cors": "^2.8.12", 20 | "@types/express": "^4.17.13", 21 | "@types/jsonwebtoken": "^8.5.6", 22 | "@types/morgan": "^1.9.3", 23 | "@types/node": "^16.7.2", 24 | "@typescript-eslint/eslint-plugin": "^4.29.3", 25 | "@typescript-eslint/parser": "^4.29.3", 26 | "eslint": "^7.32.0", 27 | "eslint-config-prettier": "^8.3.0", 28 | "eslint-plugin-prettier": "^3.4.1", 29 | "tsc-watch": "^4.5.0", 30 | "typescript": "^4.3.5" 31 | }, 32 | "dependencies": { 33 | "bcrypt": "^5.0.1", 34 | "compression": "^1.7.4", 35 | "cors": "^2.8.5", 36 | "dotenv": "^10.0.0", 37 | "envalid": "^7.2.2", 38 | "express": "^4.17.1", 39 | "helmet": "^4.6.0", 40 | "joi": "^17.4.2", 41 | "jsonwebtoken": "^8.5.1", 42 | "module-alias": "^2.2.2", 43 | "mongoose": "^6.0.12", 44 | "morgan": "^1.10.0" 45 | }, 46 | "_moduleAliases": { 47 | "@/resources": "dist/resources", 48 | "@/utils": "dist/utils", 49 | "@/middleware": "dist/middleware" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import express, { Application } from 'express'; 2 | import mongoose from 'mongoose'; 3 | import compression from 'compression'; 4 | import cors from 'cors'; 5 | import morgan from 'morgan'; 6 | import Controller from '@/utils/interfaces/controller.interface'; 7 | import ErrorMiddleware from '@/middleware/error.middleware'; 8 | import helmet from 'helmet'; 9 | 10 | class App { 11 | public express: Application; 12 | public port: number; 13 | 14 | constructor(controllers: Controller[], port: number) { 15 | this.express = express(); 16 | this.port = port; 17 | 18 | this.initialiseDatabaseConnection(); 19 | this.initialiseMiddleware(); 20 | this.initialiseControllers(controllers); 21 | this.initialiseErrorHandling(); 22 | } 23 | 24 | private initialiseMiddleware(): void { 25 | this.express.use(helmet()); 26 | this.express.use(cors()); 27 | this.express.use(morgan('dev')); 28 | this.express.use(express.json()); 29 | this.express.use(express.urlencoded({ extended: false })); 30 | this.express.use(compression()); 31 | } 32 | 33 | private initialiseControllers(controllers: Controller[]): void { 34 | controllers.forEach((controller: Controller) => { 35 | this.express.use('/api', controller.router); 36 | }); 37 | } 38 | 39 | private initialiseErrorHandling(): void { 40 | this.express.use(ErrorMiddleware); 41 | } 42 | 43 | private initialiseDatabaseConnection(): void { 44 | const { MONGO_USER, MONGO_PASSWORD, MONGO_PATH } = process.env; 45 | 46 | mongoose.connect( 47 | `mongodb://${MONGO_USER}:${MONGO_PASSWORD}${MONGO_PATH}` 48 | ); 49 | } 50 | 51 | public listen(): void { 52 | this.express.listen(this.port, () => { 53 | console.log(`App listening on the port ${this.port}`); 54 | }); 55 | } 56 | } 57 | 58 | export default App; 59 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import 'module-alias/register'; 3 | import validateEnv from '@/utils/validateEnv'; 4 | import App from './app'; 5 | import PostController from '@/resources/post/post.controller'; 6 | import UserController from '@/resources/user/user.controller'; 7 | 8 | validateEnv(); 9 | 10 | const app = new App( 11 | [new PostController(), new UserController()], 12 | Number(process.env.PORT) 13 | ); 14 | 15 | app.listen(); 16 | -------------------------------------------------------------------------------- /src/middleware/authenticated.middleware.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from 'express'; 2 | import token from '@/utils/token'; 3 | import UserModel from '@/resources/user/user.model'; 4 | import Token from '@/utils/interfaces/token.interface'; 5 | import HttpException from '@/utils/exceptions/http.exception'; 6 | import jwt from 'jsonwebtoken'; 7 | 8 | async function authenticatedMiddleware( 9 | req: Request, 10 | res: Response, 11 | next: NextFunction 12 | ): Promise { 13 | const bearer = req.headers.authorization; 14 | 15 | if (!bearer || !bearer.startsWith('Bearer ')) { 16 | return next(new HttpException(401, 'Unauthorised')); 17 | } 18 | 19 | const accessToken = bearer.split('Bearer ')[1].trim(); 20 | try { 21 | const payload: Token | jwt.JsonWebTokenError = await token.verifyToken( 22 | accessToken 23 | ); 24 | 25 | if (payload instanceof jwt.JsonWebTokenError) { 26 | return next(new HttpException(401, 'Unauthorised')); 27 | } 28 | 29 | const user = await UserModel.findById(payload.id) 30 | .select('-password') 31 | .exec(); 32 | 33 | if (!user) { 34 | return next(new HttpException(401, 'Unauthorised')); 35 | } 36 | 37 | req.user = user; 38 | 39 | return next(); 40 | } catch (error) { 41 | return next(new HttpException(401, 'Unauthorised')); 42 | } 43 | } 44 | 45 | export default authenticatedMiddleware; 46 | -------------------------------------------------------------------------------- /src/middleware/error.middleware.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from 'express'; 2 | import HttpException from '@/utils/exceptions/http.exception'; 3 | 4 | function errorMiddleware( 5 | error: HttpException, 6 | req: Request, 7 | res: Response, 8 | _next: NextFunction 9 | ): void { 10 | const status = error.status || 500; 11 | const message = error.message || 'Something went wrong'; 12 | res.status(status).send({ 13 | status, 14 | message, 15 | }); 16 | } 17 | 18 | export default errorMiddleware; 19 | -------------------------------------------------------------------------------- /src/middleware/validation.middleware.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction, RequestHandler } from 'express'; 2 | import Joi from 'joi'; 3 | 4 | function validationMiddleware(schema: Joi.Schema): RequestHandler { 5 | return async ( 6 | req: Request, 7 | res: Response, 8 | next: NextFunction 9 | ): Promise => { 10 | const validationOptions = { 11 | abortEarly: false, 12 | allowUnknown: true, 13 | stripUnknown: true, 14 | }; 15 | 16 | try { 17 | const value = await schema.validateAsync( 18 | req.body, 19 | validationOptions 20 | ); 21 | req.body = value; 22 | next(); 23 | } catch (e: any) { 24 | const errors: string[] = []; 25 | e.details.forEach((error: Joi.ValidationErrorItem) => { 26 | errors.push(error.message); 27 | }); 28 | res.status(400).send({ errors: errors }); 29 | } 30 | }; 31 | } 32 | 33 | export default validationMiddleware; 34 | -------------------------------------------------------------------------------- /src/resources/post/post.controller.ts: -------------------------------------------------------------------------------- 1 | import { Router, Request, Response, NextFunction } from 'express'; 2 | import Controller from '@/utils/interfaces/controller.interface'; 3 | import HttpException from '@/utils/exceptions/http.exception'; 4 | import validationMiddleware from '@/middleware/validation.middleware'; 5 | import validate from '@/resources/post/post.validation'; 6 | import PostService from '@/resources/post/post.service'; 7 | 8 | class PostController implements Controller { 9 | public path = '/posts'; 10 | public router = Router(); 11 | private PostService = new PostService(); 12 | 13 | constructor() { 14 | this.initialiseRoutes(); 15 | } 16 | 17 | private initialiseRoutes(): void { 18 | this.router.post( 19 | `${this.path}`, 20 | validationMiddleware(validate.create), 21 | this.create 22 | ); 23 | } 24 | 25 | private create = async ( 26 | req: Request, 27 | res: Response, 28 | next: NextFunction 29 | ): Promise => { 30 | try { 31 | const { title, body } = req.body; 32 | 33 | const post = await this.PostService.create(title, body); 34 | 35 | res.status(201).json({ post }); 36 | } catch (error) { 37 | next(new HttpException(400, 'Cannot create post')); 38 | } 39 | }; 40 | } 41 | 42 | export default PostController; 43 | -------------------------------------------------------------------------------- /src/resources/post/post.interface.ts: -------------------------------------------------------------------------------- 1 | import { Document } from 'mongoose'; 2 | 3 | export default interface Post extends Document { 4 | title: string; 5 | body: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/resources/post/post.model.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model } from 'mongoose'; 2 | import Post from '@/resources/post/post.interface'; 3 | 4 | const PostSchema = new Schema( 5 | { 6 | title: { 7 | type: String, 8 | required: true, 9 | }, 10 | body: { 11 | type: String, 12 | required: true, 13 | }, 14 | }, 15 | { timestamps: true } 16 | ); 17 | 18 | export default model('Post', PostSchema); 19 | -------------------------------------------------------------------------------- /src/resources/post/post.service.ts: -------------------------------------------------------------------------------- 1 | import PostModel from '@/resources/post/post.model'; 2 | import Post from '@/resources/post/post.interface'; 3 | 4 | class PostService { 5 | private post = PostModel; 6 | 7 | /** 8 | * Create a new post 9 | */ 10 | public async create(title: string, body: string): Promise { 11 | try { 12 | const post = await this.post.create({ title, body }); 13 | 14 | return post; 15 | } catch (error) { 16 | throw new Error('Unable to create post'); 17 | } 18 | } 19 | } 20 | 21 | export default PostService; 22 | -------------------------------------------------------------------------------- /src/resources/post/post.validation.ts: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | const create = Joi.object({ 4 | title: Joi.string().required(), 5 | 6 | body: Joi.string().required(), 7 | }); 8 | 9 | export default { create }; 10 | -------------------------------------------------------------------------------- /src/resources/user/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { Router, Request, Response, NextFunction } from 'express'; 2 | import Controller from '@/utils/interfaces/controller.interface'; 3 | import HttpException from '@/utils/exceptions/http.exception'; 4 | import validationMiddleware from '@/middleware/validation.middleware'; 5 | import validate from '@/resources/user/user.validation'; 6 | import UserService from '@/resources/user/user.service'; 7 | import authenticated from '@/middleware/authenticated.middleware'; 8 | 9 | class UserController implements Controller { 10 | public path = '/users'; 11 | public router = Router(); 12 | private UserService = new UserService(); 13 | 14 | constructor() { 15 | this.initialiseRoutes(); 16 | } 17 | 18 | private initialiseRoutes(): void { 19 | this.router.post( 20 | `${this.path}/register`, 21 | validationMiddleware(validate.register), 22 | this.register 23 | ); 24 | this.router.post( 25 | `${this.path}/login`, 26 | validationMiddleware(validate.login), 27 | this.login 28 | ); 29 | this.router.get(`${this.path}`, authenticated, this.getUser); 30 | } 31 | 32 | private register = async ( 33 | req: Request, 34 | res: Response, 35 | next: NextFunction 36 | ): Promise => { 37 | try { 38 | const { name, email, password } = req.body; 39 | 40 | const token = await this.UserService.register( 41 | name, 42 | email, 43 | password, 44 | 'user' 45 | ); 46 | 47 | res.status(201).json({ token }); 48 | } catch (error) { 49 | next(new HttpException(400, error.message)); 50 | } 51 | }; 52 | 53 | private login = async ( 54 | req: Request, 55 | res: Response, 56 | next: NextFunction 57 | ): Promise => { 58 | try { 59 | const { email, password } = req.body; 60 | 61 | const token = await this.UserService.login(email, password); 62 | 63 | res.status(200).json({ token }); 64 | } catch (error) { 65 | next(new HttpException(400, error.message)); 66 | } 67 | }; 68 | 69 | private getUser = ( 70 | req: Request, 71 | res: Response, 72 | next: NextFunction 73 | ): Response | void => { 74 | if (!req.user) { 75 | return next(new HttpException(404, 'No logged in user')); 76 | } 77 | 78 | res.status(200).send({ data: req.user }); 79 | }; 80 | } 81 | 82 | export default UserController; 83 | -------------------------------------------------------------------------------- /src/resources/user/user.interface.ts: -------------------------------------------------------------------------------- 1 | import { Document } from 'mongoose'; 2 | 3 | export default interface User extends Document { 4 | email: string; 5 | name: string; 6 | password: string; 7 | role: string; 8 | 9 | isValidPassword(password: string): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /src/resources/user/user.model.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model } from 'mongoose'; 2 | import bcrypt from 'bcrypt'; 3 | import User from '@/resources/user/user.interface'; 4 | 5 | const UserSchema = new Schema( 6 | { 7 | name: { 8 | type: String, 9 | required: true, 10 | }, 11 | email: { 12 | type: String, 13 | required: true, 14 | unique: true, 15 | trim: true, 16 | }, 17 | password: { 18 | type: String, 19 | }, 20 | role: { 21 | type: String, 22 | required: true, 23 | }, 24 | }, 25 | { timestamps: true } 26 | ); 27 | 28 | UserSchema.pre('save', async function (next) { 29 | if (!this.isModified('password')) { 30 | return next(); 31 | } 32 | 33 | const hash = await bcrypt.hash(this.password, 10); 34 | 35 | this.password = hash; 36 | 37 | next(); 38 | }); 39 | 40 | UserSchema.methods.isValidPassword = async function ( 41 | password: string 42 | ): Promise { 43 | return await bcrypt.compare(password, this.password); 44 | }; 45 | 46 | export default model('User', UserSchema); 47 | -------------------------------------------------------------------------------- /src/resources/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import UserModel from '@/resources/user/user.model'; 2 | import token from '@/utils/token'; 3 | 4 | class UserService { 5 | private user = UserModel; 6 | 7 | /** 8 | * Register a new user 9 | */ 10 | public async register( 11 | name: string, 12 | email: string, 13 | password: string, 14 | role: string 15 | ): Promise { 16 | try { 17 | const user = await this.user.create({ 18 | name, 19 | email, 20 | password, 21 | role, 22 | }); 23 | 24 | const accessToken = token.createToken(user); 25 | 26 | return accessToken; 27 | } catch (error) { 28 | throw new Error(error.message); 29 | } 30 | } 31 | 32 | /** 33 | * Attempt to login a user 34 | */ 35 | public async login( 36 | email: string, 37 | password: string 38 | ): Promise { 39 | try { 40 | const user = await this.user.findOne({ email }); 41 | 42 | if (!user) { 43 | throw new Error('Unable to find user with that email address'); 44 | } 45 | 46 | if (await user.isValidPassword(password)) { 47 | return token.createToken(user); 48 | } else { 49 | throw new Error('Wrong credentials given'); 50 | } 51 | } catch (error) { 52 | throw new Error('Unable to create user'); 53 | } 54 | } 55 | } 56 | 57 | export default UserService; 58 | -------------------------------------------------------------------------------- /src/resources/user/user.validation.ts: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | const register = Joi.object({ 4 | name: Joi.string().max(30).required(), 5 | 6 | email: Joi.string().email().required(), 7 | 8 | password: Joi.string().min(6).required(), 9 | }); 10 | 11 | const login = Joi.object({ 12 | email: Joi.string().required(), 13 | 14 | password: Joi.string().required(), 15 | }); 16 | 17 | export default { register, login }; 18 | -------------------------------------------------------------------------------- /src/utils/definitions/custom.d.ts: -------------------------------------------------------------------------------- 1 | import User from '@/resources/user/user.interface'; 2 | 3 | declare global { 4 | namespace Express { 5 | export interface Request { 6 | user: User; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/exceptions/http.exception.ts: -------------------------------------------------------------------------------- 1 | class HttpException extends Error { 2 | public status: number; 3 | public message: string; 4 | 5 | constructor(status: number, message: string) { 6 | super(message); 7 | this.status = status; 8 | this.message = message; 9 | } 10 | } 11 | 12 | export default HttpException; 13 | -------------------------------------------------------------------------------- /src/utils/interfaces/controller.interface.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | interface Controller { 4 | path: string; 5 | router: Router; 6 | } 7 | 8 | export default Controller; 9 | -------------------------------------------------------------------------------- /src/utils/interfaces/token.interface.ts: -------------------------------------------------------------------------------- 1 | import { Schema } from 'mongoose'; 2 | 3 | interface Token extends Object { 4 | id: Schema.Types.ObjectId; 5 | expiresIn: number; 6 | } 7 | 8 | export default Token; 9 | -------------------------------------------------------------------------------- /src/utils/token.ts: -------------------------------------------------------------------------------- 1 | import jwt from 'jsonwebtoken'; 2 | import User from '@/resources/user/user.interface'; 3 | import Token from '@/utils/interfaces/token.interface'; 4 | 5 | export const createToken = (user: User): string => { 6 | return jwt.sign({ id: user._id }, process.env.JWT_SECRET as jwt.Secret, { 7 | expiresIn: '1d', 8 | }); 9 | }; 10 | 11 | export const verifyToken = async ( 12 | token: string 13 | ): Promise => { 14 | return new Promise((resolve, reject) => { 15 | jwt.verify( 16 | token, 17 | process.env.JWT_SECRET as jwt.Secret, 18 | (err, payload) => { 19 | if (err) return reject(err); 20 | 21 | resolve(payload as Token); 22 | } 23 | ); 24 | }); 25 | }; 26 | 27 | export default { createToken, verifyToken }; 28 | -------------------------------------------------------------------------------- /src/utils/validateEnv.ts: -------------------------------------------------------------------------------- 1 | import { cleanEnv, str, port } from 'envalid'; 2 | 3 | function validateEnv(): void { 4 | cleanEnv(process.env, { 5 | NODE_ENV: str({ 6 | choices: ['development', 'production'], 7 | }), 8 | MONGO_PASSWORD: str(), 9 | MONGO_PATH: str(), 10 | MONGO_USER: str(), 11 | PORT: port({ default: 3000 }), 12 | }); 13 | } 14 | 15 | export default validateEnv; 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "dist", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | "baseUrl": "./src", /* Base directory to resolve non-absolute module names. */ 46 | "paths": { 47 | "@/resources/*" : ["resources/*"], 48 | "@/utils/*" : ["utils/*"], 49 | "@/middleware/*" : ["middleware/*"], 50 | }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 51 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 52 | // "typeRoots": [], /* List of folders to include type definitions from. */ 53 | // "types": [], /* Type declaration files to be included in compilation. */ 54 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 55 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 56 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 57 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 58 | 59 | /* Source Map Options */ 60 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 61 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 62 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 63 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 64 | 65 | /* Experimental Options */ 66 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 67 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 68 | 69 | /* Advanced Options */ 70 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 71 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 72 | } 73 | } 74 | --------------------------------------------------------------------------------