首页 > 其他分享 >从0开发属于自己的nestjs框架的mini 版 —— 终极篇

从0开发属于自己的nestjs框架的mini 版 —— 终极篇

时间:2023-07-30 17:44:05浏览次数:51  
标签:mini ... 中间件 ctx private nestjs error 终极 id

这篇其实是最简单的,就是将前面所实现的ioc,路由整合在一起就可以了

话不多说,直接上代码

\src\koa-ioc.ts

引入相关库


import Koa from "koa";
import koaRouter from "koa-router";
import { ContainerModule } from "./ioc-module";
import { Type } from "./ioc-core.ts";
import { ResigerRouter } from "./koa-decorator";

声明类型


/****************声明类型************ */
/**
 * 异常响应类型
 */
export type IExceptionsFilter = (
  ctx: Koa.DefaultContext,
  error: Error
) => void | any | Promise<any>;

/**
 * 成功响应类型
 */
export type IResponseInterceptor = (ctx: Koa.DefaultContext) => unknown;

/**
 * 实例参数类型
 */
interface IKoaNestOption {
  koaOption?: ConstructorParameters<typeof Koa>; // ConstructorParameters获取构造函数参数的类型
  prefix?: string;
  routerOptions?: koaRouter.IRouterOptions;
  [key: string]: any;
}

NestFactory 实现的


export class NestFactory<T> {
  [x: string]: any;

  private iocInstance: ContainerModule<T>; // ioc容器实例

  private koaInstance: Koa; // koa 实例

  private routerInstance: koaRouter; // 路由实例

  private middleWareQuence: Array<Koa.Middleware> = []; // 全局中间件

  private exceptionsFilterQuence: Array<IExceptionsFilter> = []; // 全局异常拦截器(中间件)

  private responseInterceptorQuence: Array<IResponseInterceptor> = []; // 全局响应拦截器(中间件)

  constructor(appModule: Type<T>, options: IKoaNestOption = {}) {
    const { routerOptions = {}, koaOption = {} } = options || {};

    this.iocInstance = new ContainerModule(appModule);

    this.routerInstance = new koaRouter({
      ...routerOptions,
      prefix: options.prefix,
    });

    this.koaInstance = new Koa(koaOption);
  }

  private init() {
    this.appError();
    // 加载全局中间件
    this.koaInstance.use(this.setFirstMiddleware());
    this.middleWareQuence.forEach((middleware: Koa.Middleware) =>
      this.koaInstance.use(middleware)
    );
    // 加载路由
    this.loadRoutes();
  }

  // 设置第一个中间,可以捕获(任何一个中间件异常)全局响应和错误处理
  private setFirstMiddleware = () => {
    return async (ctx: Koa.DefaultContext, next: Function) => {
      try {
        ctx.requestId = Math.random();
        await next();
        this.responseInterceptorQuence.forEach((itme) => itme(ctx));
      } catch (error) {
        ctx.app.emit("error", error, ctx);
      }
    };
  };
  /**
   * 加载路由
   */
  private loadRoutes() {
    const ctrInstance = this.iocInstance.getControllerInstance();

    ctrInstance.forEach((itme) => ResigerRouter(this.routerInstance, itme));
    this.koaInstance.use(this.routerInstance.routes());
  }

  // 监听错误响应
  private appError() {
    this.koaInstance.on("error", (error: Error, ctx: Koa.DefaultContext) => {
      this.exceptionsFilterQuence.forEach((itme) => itme(ctx, error));
    });
  }

  //添加全局中间件
  public use(...middleware: Array<Koa.Middleware>) {
    this.middleWareQuence = [...this.middleWareQuence, ...middleware];
  }

  //添加全局异常拦截器
  public setGlobalExceptionsFilter(...fn: Array<IExceptionsFilter>) {
    this.exceptionsFilterQuence = [...this.exceptionsFilterQuence, ...fn];
  }
  // 添加全局响应拦截器
  public setGlobalResponseInterceptor(...fn: Array<IResponseInterceptor>) {
    this.responseInterceptorQuence = [...this.responseInterceptorQuence, ...fn];
  }

  //服务启动
  public listen(port: number, host?: string | Function, callback?: Function) {
    this.init();
    if (typeof host == "function") {
      callback = host;
      host = "0.0.0.0";
    }
    this.koaInstance.listen(port, host, callback && callback());
  }

  public getKoa() {
    return this.koaInstance;
  }
  public getRouter() {
    return this.routerInstance;
  }
}

测试用例


import Koa from "koa";
import { Controller, GET, Query, Ctx } from "./koa-decorator";
import { NestFactory } from "./koa-ioc";
import { Module } from "./ioc-module";
import { Injectable, Inject } from "./ioc-core";

@Injectable()
class UserService {
  private data: Array<any> = [];
  constructor() {
    this.data = [{ id: 1 }, { id: 2 }, { id: 3 }];
  }
  findUser(id: number) {
    return this.data.find((item) => item.id == id);
  }
}

@Controller("user")
class UserController {

  constructor(private userService: UserService) {}

  @GET("list")
  getUserId(@Query("id") id: number, @Ctx() ctx: Koa.DefaultContext) {
    console.log("ctx", ctx, id);
    let result = this.userService.findUser(id);
    if (!result) {
      throw new Error(`用户id [${id}] 不存在`);
    }
    return result;
  }
}

@Module({
  providers: [UserService],
  controllers: [UserController],
  imports: [],
})
class AppModule {}

function start() {
  const app = new NestFactory(AppModule, { prefix: "/api" });

  // 全局响应中间件
  app.setGlobalResponseInterceptor(async (ctx) => {
    ctx.body = await { data: ctx.body, success: true, status: 200 };
  });

  // 全局异常捕获中间件
  app.setGlobalExceptionsFilter(async (ctx, error) => {
    ctx.body = await {
      data: null,
      success: false,
      status: 500,
      message: error.message ? error.message : error,
    };
  });

  app.listen(8000, () => {
    console.info("app is runing in prot 8080");
  });
}
start();



总结

1、至此,一个mini 版本的nestjs 框架就完成了
2、重提一点,这个只是学习,对于使用nestjs 也是有很大帮助的
3、在此基础是可以扩展更多的功能,比如类中间件,方法中间件,守卫,管道等等也是可以的
4、这个是基础版本,想要更完善的功能学习的,可以参考 npm i @bylive/nestjs 这个增强版的

标签:mini,...,中间件,ctx,private,nestjs,error,终极,id
From: https://www.cnblogs.com/beyonds/p/17591614.html

相关文章

  • 从0开发属于自己的nestjs框架的mini 版 —— koa-decorator路由篇
    这篇主要是实现路由注解,用过nestjs的都知道,其路由都是通过注解来实现的,如有控制器@Controller(),@Get()...等等,nestjs底层框架可选是expres或者是Fastify,在这里我选择koa2。话不多说,直接上代码src/koa-decorator.ts引入相关库import"reflect-metadata";importpathfro......
  • MinimumBoundingBox2
    [ABC297F]MinimumBoundingBox2考虑解决一个稍简单的问题。给你一个\(n\timesm\)的矩形棋盘,要在上面放\(k\)个棋子,使得矩形\(4\)条边上都要有至少一个棋子。问方案数。样例输入:222样例输出:2总方案数\(C_{n\timesm}^k\)。发现不好做,我们于是试着求解\(4......
  • 从0开发属于自己的nestjs框架的mini 版- ioc篇
    如今,nodejs的框架也是层出不穷,偏向向底层的有express、koa、Fastify,偏向于上层有阿里的Egg、thinkjs、还有国外的nestjs。在这里我更喜欢nestjs,主要是其用了不同于其他框架的思想,采用分层,AOP(面向切面编程),OOP(面向对象编程)的设计思想。如果想要自己写一个类似的框架,该......
  • centos环境minio安装踩坑指南2023年7月30日
    MinIO的安装踩坑指南环境centos71.安装MinIO官方文档Binary下载,按照官网的路径配置比较快下载miniowgethttps://dl.min.io/server/minio/release/linux-amd64/minio修改minio的权限chmod+xminio移动下载的文件到此文件夹下sudomvminio/usr/local/bin/2.......
  • 【NestJS系列】核心概念:Controller控制器
    前言控制器主要是用来处理客户端传入的请求并向客户端返回响应。它一般是用来做路由导航的,内部路由机制控制哪个控制器接收哪些请求。路由为了创建基本控制器,我们需要使用@Controller装饰器,装饰器将类与所需元数据关联起来,并使Nest能够创建路由映射。我们使用nest-cli快速创建一个R......
  • 【NestJS系列】DI依赖注入与IOC控制反转
    前言上篇文章我们学习了如何使用nest-cli来快速生成一个NestJS后端项目,当我们打开编辑器查看代码时,会发现整个代码风格有点类似JAVA的spring框架,并且你会发现一些service类在controller控制器的constructor中注入后,可以不需要手动new就可以直接使用该类对应的实例方法。比如:import......
  • 【NestJS系列】核心概念:Providers提供者
    前言Providers是Nest中的一个基本概念,许多Nest中定义的类都可以被视为一个Provider,比如:service、repository、factory、helper等,它们都可以通过constructor注入依赖关系,这就意味着类与类之间可以创建各种依赖关系,并且维护各个类之间依赖关系的工作将委托给Nest运行时系统。Provider......
  • 【NestJS系列】从Nest CLI开始入门
    初识NestJSNest是一个渐进的Node.js框架,它可以在TypeScript和JavaScript(ES6、ES7、ES8)之上构建高效、可伸缩的企业级服务器端应用程序。Nest基于TypeScript编写并且结合了OOP(面向对象编程),FP(函数式编程)和FRP(函数式响应编程)的相关理念。在设计上的很多灵感来自于Ang......
  • CentOS 7 mini安装完配置
    背景CentOS8系统2021年12月31日已停止维护服务,CentOS7系统将于2024年06月30日停止维护服务。CentOS官方不再提供CentOS9及后续版本,不再支持新的软件和补丁更新。所以我们如果要安装服务器操作系统就需要安装centos7。这里我是用虚拟机安装的centos7mini版,mini版本是最小化安......
  • Flutter是跨平台开发终极之选吗?Android开发该如何快速上手Flutter?
    跨端技术是Android程序员乃至所有移动开发程序员一直在研究的课题。3月4日,谷歌正式发布了Flutter的2.0。该版本最大的特性就是可以支持五大主流的操作系统:iOS、Android、Linux、Windows和MacOS。官方甚至还说丰田将会把Flutter带到汽车中。也就是说,我们可以用一套Flutter......