Skip to content

Latest commit

 

History

History
891 lines (688 loc) · 30.5 KB

NOTE.md

File metadata and controls

891 lines (688 loc) · 30.5 KB

Introduction

If you’re familiar with Node.js basics, start by running the code. As you explore and read the comments, you’ll gradually understand how it works.

  • Click on the header it will redirect to the respective codebase, download the code and run it.

⁙⫸ This boilerplate is perfect for starting a project without any schema, controller, routes, or authentication.

Getting Started:

  1. Setup: Rename the .env.example to .env and replace the MONGO_URL="" with your own MongoDB URL.
  2. Installation: Run npm install or yarn install to install the necessary dependencies.
  3. Running the Project: Use npm run dev or yarn dev to start the project.

Additional Information:

  • If any dependency is missing, install it manually.
  • If any dependency needs to be updated, update it manually or use npm outdated or yarn outdated to check the outdated dependencies. Then use npm update or yarn update to update the dependencies.
  • You can change the port number in the .env file as per your requirements.

⁙⫸ With Authentication + User Operations

Understanding the Flow:

  • Receive an email and password from the user.
  • Hash the password for security.
  • Save the email and hashed password in the database.
  • When the user logs in with their email and password, verify the credentials.
  • If the credentials are valid, generate a session token.
  • Send the session token to the client.
  • The client stores the token and sends it back in the header for subsequent requests.
  • For each request, verify the session token.
  • If the token is valid, process the request and send the data to the client.

Contents:

  • User Schema (Mongoose): Includes email, username, and authentication (which consists of password, salt, and sessionToken).
  • User Type Defined
  • Middleware: This includes two types:
    • Owner: Ensures the user is the owner of the account.
    • Authenticated: Ensures the user is authenticated.
    • Error Handler: Handles the error.
  • Utils: This includes crypto for salt and hash password and generate session token.
  • Controller: This includes auth (with register and login methods) and User ( with getAllUser, updateUserById, and deleteUserById methods).

Routes:

  • Auth
    • register: POST request to /api/v1/auth/register
      • Example body:
      {
        "email": "[email protected]",
        "password": "Subham@123#86!GitHub_DeVeLoPeR",
        "username": "Subham"
      }
    • login: POST request to /api/v1/auth/login
      • Example body:
      {
        "email": "[email protected]",
        "password": "Subham@123#86!GitHub_DeVeLoPeR",
        "username": "Subham"
      }
  • User
    • getAllUser: GET request to /api/v1/users. This is wrapped with the authentication middleware, so you need to log in first to get the data.
    • updateUserById: PATCH request to /api/v1/users/{id}. This is wrapped with the authentication and owner middleware, so you need to log in first to update the data.
      • Example body:
      {
        "username": "XAM"
      }
    • deleteUserById: DELETE request to /api/v1/users/{id}. This is wrapped with the authentication and owner middleware, so you need to log in first to delete the data.

Frontend: Next.js

Backend: Express.js

Introduction:

  • Access Token: A short-lived token that is used to access protected resources on behalf of the user.
  • Refresh Token: A long-lived token that is used to refresh the access token when it expires.
  • JWT - JWT is a string that has three parts separated by dots. Each part is a base64url encoded string of the header, payload, and signature.
    • JWT - HEADER.PAYLOAD.SIGNATURE

      • HEADER - "alg": "HS256", "typ": "JWT"
      • PAYLOAD - sessionID: "1234567890", "email": "[email protected]", "username": "Subham"(Don't store sensitive data like password)
      • encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64')
      • SIGNATURE - crypto.createHmac('sha256', secret).update(encodedHeader + '.' + encodedPayload).digest('base64')

Understanding the Flow:

⁙⫸ With Authentication + User Operations

Understanding the Flow:

JWT

  • User logs in with their credentials (username, password, etc.).
  • Server verifies the credentials. If they're valid, the server generates an Access Token and a Refresh Token.
  • The Access Token is a short-lived token (usually about 15 minutes to 1 hour) that carries the user information necessary to access a resource.
  • The Refresh Token is a long-lived token (usually about 2 weeks to 6 months) that's used to request new Access Tokens.
  • The Server sends both tokens to the client.
  • Client stores the tokens. The Access Token is used for making authenticated requests.
  • When the Access Token expires, the client uses the Refresh Token to request a new Access Token.
  • Server verifies the Refresh Token and issues a new Access Token (and possibly a new Refresh Token).
  • If the Refresh Token is expired or invalid, the user will need to authenticate again to get a new pair of tokens.

TOKEN Mechanism:

Instructions:

You will get two folders[Stateful , Stateless] in model,middleware,routes,utils and controller folder.

  • Stateful: This is the cookie-based authentication with server token.
  • Stateless: This is the JWT-based authentication with access token and refresh token.

purpose : To understand the difference between stateful and stateless authentication.

Contents:

  • Client: This includes our frontend code using Next.js 14
  • Server: Here you will get all the server-side code.
Client:
  • Components

    • Username

      • Formik Validation
      • Toast (initialValues, validate)
      • Error Handling (Yup)
      • Types (validation.ts)
      • Redux (userSlice)- For storing the username
      • Username Validation using API (Check if the username is already present in the database or not only authorized/register users from the database are permitted to proceed to the next page)
    • Password

      • Formik Validation
      • Toast (initialValues, validate)
      • Error Handling (Yup)
      • Types (validation.ts)
      • V1(Async Thunk and AXIOS ) and V2 (RTK Query and js-cookie and AXIOS)—For storing the access token and refresh token (Both implementations are correct, but V2 is the best practice)
    • Recovery

      • OTP to reset password
      • OTP verification
    • Reset

      • Formik Validation
      • Toast (initialValues, validate)
      • Error Handling (Yup)
      • Types (validation.ts)
      • Reset Password using API
      • Handle the error (API)
      • Handle the ResetSession (API)
    • Register (Register User)

      • Convert: convert the file to a Base64 string
      • Formik Validation
      • Toast (initialValues, validate , User Existence)
      • Error Handling (Yup)
      • Types (validation.ts)
      • Email Send API
      • Register User using API
      • Delete Profile Picture
      • Get a Profile Picture
      • Hook - useMutation (react-query)
      • Hook - useQuery (react-query)
      • S3 Bucket (AWS) (READ HERE - S3 Bucket)
    • Profile

      • Convert: convert the file to a Base64 string
      • Formik Validation
      • Toast (initialValues, validate)
      • Error Handling (Yup)
      • Types (validation.ts)
      • Refresh Token (Cookie) & Access Token (Redux Store)
      • Use RTK Query (react-query) for put request (update user data)
      • Use RTK Query (react-query) for get access token and refresh token
      • Redux Persist (Redux Toolkit)—For storing the access token when the user refreshes the page it will not log out the user
      • Username from token (JWT Decode) (Fetch Hook)
  • api - Using Axios (Custom Hooks)

    • Authentication: For checking the user is authenticated or not
    • Auth:
      • Login: Log in the user
      • Register: Register the user
      • Reset Password: Reset the password
    • Mail:
      • Send Mail: Send mail to the user according to the user action
    • OTP:
      • Generate OTP: Generate OTP for the user
      • Verify OTP: Verify the OTP
    • User
      • Get User: Get the user data
      • Update User: Update the user data
      • Delete Profile Picture: Delete the profile picture from the S3 bucket
      • Get Profile Picture: Get the profile picture from the S3 bucket
  • REDUX - Using Redux Toolkit

    • user-userSlice-For storing the username
    • user-profilePicOwnerSlice-For storing the profile picture owner
  • Hook

    • axios—for making the API call
    • fetch—useFetch (custom hook) for fetching user data
    • useMutation—useMutation (react-query) for updating the user data
    • useQuery—useQuery (react-query) for fetching user data
  • Middleware - Protected Routes (User, Profile)

Server:
  • User Type Defined
  • User Schema (Mongoose): Includes username, password, email, firstName, lastName, mobile, address, profile.
  • utils:
    • bcrypt—for hashing the password
    • token - jwtAccess (create access token), jwtRefresh (create refresh token), tokenEncrypt (encrypt the token), tokenDecrypt (crupto for encrypt and decrypt the refresh token) , tokenVerify (verify the token) , saveToken (save the Refresh Token in the database) jwtSign(sign the token) , jwtVerify(verify the token)... more
    • mail - sendMail (send mail to the user)(nodemailer) normal mail and template mail
    • gmail-smtp - sendGMail (send mail to the user)(nodemailer) normal mail and template mail
    • gmail0Auth - sendGMail0Auth (send mail to the user)(nodemailer) normal mail and template mail - Check all the steps in 0AuthSetps.md
  • Middleware:
    • Owner: Ensures the user is the owner of the account.
    • Authenticated: Ensures the user is authenticated and the token is valid.
    • Error Handler: Handles the error.
  • Controller: This includes
    • auth - register(register a user), login(log in a user), generateAccessTokenHandler(Refresh Token Generate), logoutHandler(Clear token),verifyUser(verify if the user exists in the database before login), checkUserExistence (check if the user exists in the database)
    • user - getUser(get user data without a password), updateUser(update user data)
    • OTP - generateOTP(Generate OTP), verifyOTP(Verify the OTP)
  • Routes:
    • Auth

      • register: POST request to /api/v2/auth/register
      • Example body:
               {
                 "username" : "codexam_123",
                 "password" : "Codexam@123",
                 "email": "[email protected]",
                 "firstName" : "Subham",
                 "lastName": "Maity",
                 "mobile": "1234567890",
                 "address" : "india",
                 "profile": ""
                }
      • login: POST request to /api/v2/auth/login wrap with verifyUser controller
      • Example body:
              {
               "username" : "codexam_123",
               "password" : "Codexam@123"
               }
      • reset password: PUT request to /api/v2/auth/resetPassword wrap with verifyUser controller
      • But before that you have to generate OTP and verify it then you can reset the password
      • api/v2/auth/generateOTP?username=codexam_123
      • api/v2/auth/verifyOTP?username=codexam_123&code=427638
      • Then you can reset the password
      • Example body:
           {
            "username" : "codexam_123",
            "password" : "Codexam@123"
            }
    • Auth/VerifyUser

      • POST request to /api/v2/auth/verifyUser
      • Example body:
             {
               "username" : "codexam_123"
             }
      • logout: DELETE request to /api/v2/auth/token
      • Example body:
             {
               "refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
             }
    • Auth/Token

      • get refressToken: POST request to /api/v2/auth/token
      • Example body:
             {
               "refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
             }
      • logout: DELETE request to /api/v2/auth/token
      • Example body:
             {
               "refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
             }
    • User

      • get User: GET request to /api/v2/user/codexam_123 here codexam_123 is the username
      • update User: PUT request to /api/v2/updateuser?id=658ec47dcb30d4ea193d457a here 658ec47dcb30d4ea193d457a is the id wrap with authenticated and owner middleware
      • Example body:
             {
               "username" : "codexam_123",
               "password" : "Codexam@123",
               "email": "[email protected]"
             }
            
    • Auth/OTP

      • get OTP: GET request to /api/v2/auth/generateOTP?username=codexam_123 here codexam_123 is the username you have to pass in the query parameter and wrap with authenticated middleware
      • verify OTP: GET request to http://localhost:5050/api/v2/auth/verifyOTP?username=codexam_123&code=427638 here codexam_123 is the username and 427638 is the OTP you have to pass in the query parameter and wrap with authenticated middleware
    • Auth/createResetSession

      • get Session Flag: GET request to /api/v2/auth/createResetSession you will get flag true or false if the flag is true then you can reset the password
    • MAIL/EMAIL

      • send mail: POST request to /api/v2/mail-v1/registerMail
      • Example body:
              {
               "username" : "codexamA_123",
               "userEmail" : "[email protected]",
               "text" : "New User Registered",
               "subject" : "New User Registered"
              }
    • MAIL/GMAIL/SMTP

    • Go to https://myaccount.google.com/security

    • Enable 2-Step Verification

    • Create App Password https://myaccount.google.com/apppasswords

      • send mail: POST request to /api/v2/mail-v1/registerGMail
      • Example body:
              {
               "username" : "codexamA_123",
               "userEmail" : "[email protected]",
               "text" : "New User Registered",
               "subject" : "New User Registered"
              }
    • MAIL/GMAIL/0Auth Check all the steps in 0AuthSetps.md

      • send mail: POST request to /api/v2/mail-v1/registerGMail0Auth
      • Example body:
              {
               "username" : "codexamA_123",
               "userEmail" : "[email protected]",
               "text" : "New User Registered",
               "subject" : "New User Registered"
              }
    • S3 Bucket Check all the steps in S3 Setup and also understand how I set up the S3 bucket in the frontend and backend Here

      • Get Owner Profile Pic: POST request to /api/v2/storage-v1/s3/get-owner-image
      • post with user's profile data
      • Example body:
         {
           "requestedImageName":"4515e1be62e98"
         }
      • Get Owner Profile Pic: POST request to /api/v2/storage-v1/s3/get-owner-image
      • post with user's profile data
      • Example body:
         {
           "requestedImageName":"4515e1be62e98"
         }
      • Delete Owner Profile Pic: POST request to /api/v2/storage-v1/s3/remove-owner-image
      • post with user's profile data
      • Example body:
         {
           "requestedImageName":"4515e1be62e98"
         }
      • Register User Profile Pic: POST request to /api/v2/storage-v1/s3/images
        • post with image data in binary format
      • Get User Profile Pic: GET request to /api/v2/storage-v1/s3/images
        • Give you last uploaded image key
      • Delete All Keys: DELETE request to /api/v2/storage-v1/s3/clear-database-s3
        • Delete all the keys from the database

Sure, here's a more structured and detailed version of your content:

Introduction:

Redis is an open-source, in-memory key-value data store. It is versatile and can be used as a database, cache, and message broker. Redis supports various data structures such as Strings, Hashes, Lists, Sets, and more. It provides high availability via Redis Sentinel and automatic partitioning across multiple Redis nodes with Redis Cluster.

Installation:

  1. Download Docker Desktop from the official Docker website.
  2. Install Docker Desktop and open it.
  3. Open the terminal and run the following command to start the Redis server and Redis Commander:
docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest

This command will run the Redis server on port 6379 and Redis Commander on port 8001.

  1. Open a web browser and navigate to localhost:8001 to view the Redis Commander.
  2. Go back to the terminal and run docker ps to check if the Redis server is running. If it's not, run docker start redis-stack.

Now, you can use the Redis server in your project.

Redis CLI Commands:

  1. Run docker ps in the terminal to check the running container and copy the container id.
  2. Use docker exec -it <container_id> bash to open the bash terminal of the container. For example: docker exec -it 7b7e bash.
  3. Type redis-cli to open the Redis CLI terminal.
  4. Type ping to check if the Redis server is running. If you get PONG, then the server is running.

Nodejs Setup

  1. open the 5.redis folder and run the following command
npm run string
npm run list
npm run set
npm run hash
npm run sortedset
npm run stream
npm run bitmap
npm run geo
npm run pubsub
npm run dev 
  1. open the server/src/client.ts setup the redis client
import Redis from "ioredis";

const client = new Redis({
    host: 'localhost', // replace with your host, if not localhost
    port: 6379  // replace with your port, if not 6379
});

export default client;
  1. open the 5.redis folder and you will get the following files
  • string.ts
  • list.ts
  • set.ts
  • hash.ts
  • sortedset.ts
  • stream.ts
  • bitmap.ts
  • geo.ts
  • pubsub.ts
  • src/client.ts
  • src/todos.ts

Time complexity, Limitations, Use cases

Click HERE

Data Types

String Data Structure:

Click HERE

List Data Structure:

Click HERE

Set Data Structure:

Click HERE

Hash Data Structure:

Click HERE

REDIS STREAMS OPERATIONS

Click HERE

Redis Bitmaps

Click HERE

Geospatial Operations

Click HERE

Probabilistic Data Structures

You can use probabilistic data structures to store elements with a probability of false positives. It is similar to a set in other programming languages. Probabilistic data structures are often used to implement other data structures like bloom filters.

READ HERE: https://redis.io/docs/data-types/probabilistic/t-digest/

Time Series Data Structures

A time series data structure is a collection of elements with a timestamp. It is similar to a map in other programming languages. Time series data structures are often used to implement other data structures like time series.

READ HERE: https://redis.io/docs/data-types/timeseries/

Pub/Sub

Click HERE

Scale A Node.js Application With Redis

  1. Step 1. Initialize a Node.js project.
  • Copy the template what I already created for you.
  • npm i
  • replace the .env file with your own database credentials.
  • npm start to run the project.
  1. Third party api: https://jsonplaceholder.typicode.com/todos
  • We will try to speed up the api response time using redis.
  • npm i axios to install axios.
  1. Open server/src folder makes a new file todos.ts
import express from "express";
import axios from "axios";

const todos = express.Router();

todos.get("/todos", async (req, res) => {
  try {
    const { data } = await axios.get("https://jsonplaceholder.typicode.com/todos");
    res.json(data);
  } catch (error:any) {
    console.error("Error fetching todos:", error.message);
    res.status(500).json({ error: "Internal Server Error" });
  }
});

export default todos;
  1. Open server/src/app.ts and add the route to the express app.
app.use("/api/v1/", todos);
  1. now run npm run dev and go to http://localhost:5050/api/v1/todos to see the response.

  2. I have already setup Morgan for logging for response times, however, you can open Postman and check the response times.

  3. In the first fetching it takes 403ms to fetch the data from the api, and after multiple requests, it takes 120ms–351ms to fetch the data from the api.

  4. Now try to implement caching using redis.

    • you can find the client.ts file in the server/src folder.
       import Redis from "ioredis";
      
       const client = new Redis(
         {
          host: 'localhost', // replace with your host, if not localhost
          port: 6379  // replace with your port, if not 6379
         }
        );
       export default client;
    • Now open server/src/todos.ts and import the redis client.
       import client from "./client";
         
       todos.get("/todos", async (req, res) => {
            try {
              const todos = await client.get("todos");
              if (todos) {
                console.log("Fetching from redis");
                return res.json(JSON.parse(todos));
              }
              const { data } = await axios.get("https://jsonplaceholder.typicode.com/todos");
              client.set("todos", JSON.stringify(data));
              console.log("Fetching from api");
              res.json(data);
            } catch (error:any) {
              console.error("Error fetching todos:", error.message);
              res.status(500).json({ error: "Internal Server Error" });
            }
       });
       
    • Now run npm run dev and go to http://localhost:5050/api/v1/todos to see the response.
    • In the first fetching it takes 403ms to fetch the data from the api, and after multiple requests, it takes 0ms–1ms to fetch the data from the redis.
    • you can also add client.set("todos", JSON.stringify(data), "EX", 10) to set the expiration time of the key.
    • Now open you redis-cli and run keys * to see the keys and ttl todos to see the expiration time of the key.
    • If you open redis-stack container, you can see the todos with data.
    • Now you can scale your application by adding multiple instances of the application and using redis to cache the data.

Install the required packages

npm i -g @nestjs/cli

then run

npm install

Note: if you get red underline in the code editor, you can add the following line in the .eslintrc.js file

'prettier/prettier': ['error', { endOfLine: 'auto' }],
  rules: {
    'prettier/prettier': ['error', { endOfLine: 'auto' }],
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
  },

Let's understand basic structure of the application

  • src/main.ts is the entry point of the application, and it uses the NestFactory to create a new instance of the application.

in simple words, it's the main file of the application, where the application starts.

  • src/app.module.ts is the root module of the application, and it uses the @Module decorator to define the module.
    • In NestJS, a @Module is a class that is annotated with the @Module() decorator.
      • providers: The providers that will be instantiated by the Nest injector and that may be shared at least across this module.
      • controllers: The set of controllers defined in this module which have to be instantiated.
@Module({
  imports: [], // import other modules here
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {} //export the module class here
  • src/app.controller.ts is a basic controller that uses the @Controller decorator to define the controller.
    • In NestJS, a @Controller is a class that is annotated with the @Controller() decorator.
      • The @Controller() decorator is used to define a basic controller.
      • The @Get() decorator is used to define a basic GET request.
      • The @Post() decorator is used to define a basic POST request.
      • The @Put() decorator is used to define a basic PUT request.
      • The @Delete() decorator is used to define a basic DELETE request.
      • The @Patch() decorator is used to define a basic PATCH request.
      • The @Options() decorator is used to define a basic OPTIONS request.
      • The @Head() decorator is used to define a basic HEAD request. (This decorator is used to define a route that matches the HTTP HEAD request method.)
      • The @All() decorator is used to define a basic ALL request. (This decorator is used to define a route that matches any HTTP request method.)
import { Controller, Get, Post, Put, Delete, Patch, Options, Head, All } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  @Post()
  postHello(): string {
    return this.appService.postHello();
  }

  @Put()
  putHello(): string {
    return this.appService.putHello();
  }

  @Delete()
  deleteHello(): string {
    return this.appService.deleteHello();
  }

  @Patch()
  patchHello(): string {
    return this.appService.patchHello();
  }

  @Options()
  optionsHello(): string {
    return this.appService.optionsHello();
  }

  @Head()
  headHello(): string {
    return this.appService.headHello();
  }

  @All()
  allHello(): string {
    return this.appService.allHello();
  }
}
  • src/app.service.ts is a basic service that uses the @Injectable decorator to define the service.
    • In NestJS, a @Injectable is a class that is annotated with the @Injectable() decorator.
      • The @Injectable() decorator is used to define a basic service.
      • The @Inject() decorator is used to inject a service into another service.
      • The @InjectRepository() decorator is used to inject a repository into a service.
      • The @InjectConnection() decorator is used to inject a connection into a service.
      • The @InjectModel() decorator is used to inject a model into a service.
      • The @InjectQueue() decorator is used to inject a queue into a service.
      • The @InjectPipes() decorator is used to inject pipes into a service.
      • The @InjectFilters() decorator is used to inject filters into a service.
      • The @InjectInterceptors() decorator is used to inject interceptors into a service.
      • The @InjectGuards() decorator is used to inject guards into a service.
      • The @InjectExceptionFilters() decorator is used to inject exception filters into a service.
      • The @InjectHost() decorator is used to inject the host into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
      • The @InjectExecutionContext() decorator is used to inject the execution context into a service.
import { Injectable } from '@nestjs/common';

@Injectable()  

export class AppService {
  getHello(): string {
    return 'Hello World!';
  }

  postHello(): string {
    return 'Hello World!';
  }

  putHello(): string {
    return 'Hello World!';
  }

  deleteHello(): string {
    return 'Hello World!';
  }

  patchHello(): string {
    return 'Hello World!';
  }

  optionsHello(): string {
    return 'Hello World!';
  }

  headHello(): string {
    return 'Hello World!';
  }

  allHello(): string {
    return 'Hello World!';
  }
}
  • src/app.controller.spec.ts is a basic test file that uses the @nestjs/testing package to test the controller.

  • src/app.service.spec.ts is a basic test file that uses the @nestjs/testing package to test the service.

  • src/app.e2e-spec.ts is a basic test file that uses the @nestjs/testing package to test the application end-to-end.

Start the application

npm run start:dev
nest -g module <module-name>
nest -g controller <controller-name>
``
```bash
nest -g service <service-name>
nest -g pipe <pipe-name>
nest -g guard <guard-name>
nest -g filter <filter-name>
nest -g interceptor <interceptor-name>
nest -g middleware <middleware-name>
nest -g exception <exception-name>
nest -g decorator <decorator-name>
nest -g gateway <gateway-name>
nest -g resolver <resolver-name>