Skip to content

Final Project on ITSS Linux System And Network Management : A boilerplate/starter project for quickly building RESTful APIs using Node.js, Express, and Mongoose.

License

Notifications You must be signed in to change notification settings

ITSS-Linux-System-Final-Project/typescript-node-express-boilerplate

Repository files navigation

RESTful API Node Server Boilerplate

A boilerplate/starter project for quickly building RESTful APIs using Node.js, Express, and Mongoose.

By running a single command, you will get a production-ready Node.js app installed and fully configured on your machine. The app comes with many built-in features, such as authentication using JWT. For more details, check the features list below.

Installation

If you would still prefer to do the installation manually, follow these steps:

Clone the repo:

git clone https://github.com/ITSS-Linux-System-Final-Project/typescript-node-express-boilerplate.git
cd typescript-node-express-boilerplate

Install the dependencies:

npm i

Set the environment variables:

cp .env.example .env

# open .env and modify the environment variables (if needed)

Table of Contents

Features

  • Typesript
  • NoSQL database: MongoDB object data modeling using Typegoose
  • Authentication and authorization: using JWT
  • Validation: data validation using class-validator Joi
  • Error handling: centralized error handling mechanism
  • API documentation: with swagger-jsdoc and swagger-ui-express
  • Process management: advanced production process management using PM2
  • Dependency management: with NPM
  • Environment variables: using dotenv and cross-env
  • Security: set security HTTP headers using helmet
  • Santizing: sanitize request data against xss and query injection
  • CORS: Cross-Origin Resource-Sharing enabled using cors
  • Docker support
  • Linting: with ESLint and Prettier
  • Editor config: consistent editor configuration using EditorConfig

Commands

Running locally:

npm run build
node dist/app.js

Environment Variables

The environment variables can be found and modified in the .env file. They come with these default values:

# Environment, should be set to `production` for production use
NODE_ENV=

# Server port
PORT=

# MongoDB
MONGODB_CONN_STRING=

# Redis
REDIS_HOST=
REDIS_PORT=

# JWT (Time unit is default to ms if not specified)
JWT_SECRET=
JWT_EXPIRES_IN=
JWT_REFRESH_SECRET=
JWT_REFRESH_EXPIRES_IN=

# Swagger UI
# Enables /docs route for Swagger UI if set to `true`
SWAGGER_UI_ENABLED=
SWAGGER_UI_USERNAME=
SWAGGER_UI_PASSWORD=


# mailer
MAIL_PORT=
MAIL_HOST=
MAIL_USER=
MAIL_PASS=

#HTML Email Template path to get to mailTemplates directory
HTML_FILES_ROOT=

#WEBSITE Domain path
WEBSITE_DOMAIN_PATH=

Project Structure

src\
 |--config\         # Environment variables and configuration related things
 |--users\          # Structure your solution by components
 |--auth\           # Structure your solution by components
 |--utils\          # Utility classes and functions shared between components
 |--.eslintrc       # ESLint config
 |--app.js          # Express app

Token interface

{
  "email": "[email protected]",
  "role": "admin"
}

Redis storage

Authentication

Key Value TTL
auth:${email}:${refreshToken} ${accessToken} Refresh token's duration

API Documentation

To view the list of available APIs and their specifications, run the server and go to http://localhost:3000/docs in your browser. This documentation page is automatically generated using the swagger definitions written as comments in the route files.

API Endpoints

List of available routes:

Auth routes:
POST /auth/login - login
POST /auth/refresh-tokens - refresh auth tokens
POST /auth/logout -logout and delete token
User routes:
GET /user - get current logged in user
POST /user - register new user
PATCH /user/change/password - change user password
PUT /user/change/profile - change user profile
GET /user/register/verify/:active_token - verify user token (when register and mail to user)
GET /user/forgot-password/verify/:active_token - verify user token (when using forgot password function and mail to user)
POST /user/forgot-password - send reset password request

Error Handling

The app has a decentralized error handling mechanism. The error handling is on each components

// below script is on *.controller.ts files
try {
      await this.userService.changePassword(user._id, changePasswordDto);
      return {
        message: 'Success',
      };
    } catch (e) {
      throw new BadRequestError(e.message);
    }
});

You can throw error on business logic layer (*.service.ts)

async getUserByID(user_id: string) {
    const query = {
      _id: user_id,
    };
    const user = await this.userRepository.getUserDetailById(query);
    if (!user) {
      throw new NotFoundError('This User does not exist !');
    }
    return user;
  }

Validation

Request data is validated using class-validator. Check the documentation for more details on how to write validations

import { Expose } from 'class-transformer';
import { IsString, IsNotEmpty, MinLength, MaxLength } from 'class-validator';

export class ChangePasswordDto {
  @Expose()
  @IsNotEmpty()
  @IsString()
  @MinLength(4)
  @MaxLength(30)
  old_password: string;

  @Expose()
  @IsNotEmpty()
  @IsString()
  @MinLength(4)
  @MaxLength(30)
  new_password: string;
}

Authentication

To require authentication for certain routes, you can use the @Authorized([Roles]) decorator (this boilerplate always required roles to authenticate, so it will authenticate and authorize at the same time).

  @Get('', { transformResponse: false })
  @OpenAPI({
    security: [{ BearerAuth: [] }],
    description: 'Gets details of current logged-in user  ',
  })
  @Authorized(['admin', 'staff'])
  getUserByEmail(@CurrentUser({ required: true }) user: UserDocument) {
    return this.userService.getUserByEmail(user.email);
  }

These routes require a valid JWT access token in the Authorization request header using the Bearer schema. If the request does not contain a valid access token, an Unauthorized (401) error is thrown.

Generating Access Tokens:

An access token can be generated by making a successful call to login (POST /auth/login) endpoints. The response of these endpoints also contains refresh tokens (explained below).

An access token is valid for 30 minutes. You can modify this expiration time by changing the JWT_EXPIRES_IN environment variable in the .env file.

Refreshing Access Tokens:

After the access token expires, a new access token can be generated, by making a call to the refresh token endpoint (POST /auth/refresh-tokens) and sending along a valid refresh token in the request body. This call returns a new access token and a new refresh token.

A refresh token is valid for 30 days. You can modify this expiration time by changing the JWT_REFRESH_EXPIRES_IN environment variable in the .env file.

Authorization

The @Authorized([Roles]) can also be used to require certain rights/permissions to access a route.

@OpenAPI({
    security: [{ BearerAuth: [] }],
    description: 'Change password of current logged-in user',
  })
  @Authorized(['admin', 'staff']) // Each route will have independent roles required to be called
  @Patch('/change/password')
  async changePassword(
    @CurrentUser({ required: true }) user: UserDocument,
    @Body() changePasswordDto: ChangePasswordDto,
  ) {
    try {
      await this.userService.changePassword(user._id, changePasswordDto);
      return {
        message: 'Success',
      };
    } catch (e) {
      throw new BadRequestError(e.message);
    }
  }

If the user making the request does not have the required permissions to access this route, a Forbidden (403) error is thrown.

Linting

Linting is done using ESLint and Prettier.

In this app, ESLint is configured to follow the Airbnb JavaScript style guide with some modifications. It also extends eslint-config-prettier to turn off all rules that are unnecessary or might conflict with Prettier.

To modify the ESLint configuration, update the .eslintrc file. To modify the Prettier configuration, update the .prettierrc file.

To prevent a certain file or directory from being linted, add it to .eslintignore and .prettierignore.

To maintain a consistent coding style across different IDEs, the project contains .editorconfig

Contributing

Contributions are more than welcome! Please check out the contributing guide.

Inspirations

License

MIT

About

Final Project on ITSS Linux System And Network Management : A boilerplate/starter project for quickly building RESTful APIs using Node.js, Express, and Mongoose.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published