第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

如何在NestJS中使用`@nestjs-effect`庫(kù)

標(biāo)簽:
Node.js

一种在_NestJS_框架中处理副作用的方法

几个月前,我发表了第一篇文章,探讨了如何将_Effect_与_NestJS_集成。尽管它意外地得到了积极的反馈,但我感觉文章没有为读者提供足够的指导来全面拥抱_Effect_生态系统。

我已经带来了完整且可以直接执行的解决方案,旨在简化你们的采用流程。

@nestjs-effect - 一个基于 NestJS 的效果库

Effectul 是 NestJS 中的第一个库。

它提供了即插即用的功能

  • 一个专门的运行时,用于在您的应用边界执行 Effect 脚本或功能,且 无需任何手动设置(支持 HTTP、RPC 和 WebSocket 协议等)
  • 自动检测并集成您的 Effect 服务到 NestJS 依赖注入系统
  • 与不使用 Effect 的标准 NestJS 核心包和库 完全兼容
  • 通过管道机制,对 DTO 进行根据 Effect 架构的验证

本文将通过实际演示和提出实施建议来探讨解决方案的所有功能。

模块和运行时环境

库最重要的特性之一是在应用程序的边界能够自动运行Effect,这能够大大减少在_Nestjs_中使用_Effect_时的样板代码和困惑。

它通过提供一个自定义的 EffectRuntimeInterceptor 实现,该拦截器会运行效果,如果需要的话会映射值/错误,并提供 NestJS 服务上下文中的 Effect(如有),这可能包括 Effect 或非 Effect 类型的服务。

我们来举一个例子。

首先让我们来安装核心模块

npm i @nestjs-effect/core

注:npm 是 Node.js 的包管理器,用于安装和管理软件包。

然后在应用程序模块中设置模块。

    // app.module.ts

    // 引入Effect模块
    import { EffectModule } from '@nestjs-effect/core';

    @Module({
      // 注意这里
      imports: [EffectModule.forRoot()], 
      controllers: [AppController],
      providers: [],
    })
    export class AppModule {}

EffectModule 的所有选项 可以在处找到

最后在你想让效果自动运行的地方添加 EffectRuntimeInterceptor。它可以全局设置在 AppModule 中,也可以局部设置在控制器或方法内部。

由控制者:

    // app.controller.ts  
    import { EffectRuntimeInterceptor } from '@nestjs-effect/core';  

    @Controller()  
    @UseInterceptors(EffectRuntimeInterceptor) // 此处  
    export class AppController {  
      constructor() {}  

      @Get()  
      @UseInterceptors(EffectRuntimeInterceptor) // 或者此处  
      getHello(): Effect.Effect<number> {  
        return Effect.succeed(1)  
      }  
    }

按模块分类

    // app.module.ts
    import { EffectModule, EffectRuntimeInterceptor } from '@nestjs-effect/core';

    @Module({
      imports: [EffectModule.forRoot()],
      controllers: [AppController],
      providers: [
        {
          provide: APP_INTERCEPTOR,
          useClass: EffectRuntimeInterceptor, // 这里
        },
      ],
    })
    export class AppModule {}

就这样。行了。你现在可以在控制器里返回一个 Effect 了。

我们来把控制器改为返回更有意思的Effect

@Controller()  
export class AppController {  
  constructor() {}  

  @Get()  
  getHello(): Effect.Effect<{ ok: boolean; data: string }> {  // 获取问候信息的方法
    return Effect.succeed({  // 表示一个效果,包含成功状态和数据
      ok: true,  
      data: 'Hello World',  // 输出"你好,世界"
    });  
  }  
}

如果你调用这个端点,你会得到

    {  
        "ok": true,  
        "data": "你好,世界!"  
    }

这也有效,即使你发送失败的消息,就像下面这样。

@Controller()  
export class AppController {  
  constructor() {}  

  @Get()  
  getHello(): Effect.Effect<never, string> {  
    return Effect.fail('返回错误');  
  }  
}

会返回

{  
    "statusCode": 500,  
    "message": "服务器错误"  
}

默认情况下不会显示错误消息,以防止泄露给用户。

为了映射所发送的错误(或值),我们可以使用模块中的选项:

  • mapValue(映射值)
  • mapError(映射错误)

这都在核心错误处理中详细说明。

NestJSEffect 的一个重要方面是它们的依赖注入(DI),虽然它们不能完全无缝协作,但我们可以在旁边使用它们。

我们来看一个例子,在这个例子中,我们需要在我们的_Effect_中提供一个自定义服务。

// 随机服务的 TypeScript 代码示例

@Injectable() // 注解,表示此服务可以被依赖注入
export class Random extends Context.Tag('MyRandomService')< // 扩展 Context.Tag
  Random, // 随机类
  { readonly next: Effect.Effect<number> } // next 是一个返回数字的 Effect 类型
> () {}
    // app.module.ts  

    @Controller()  
    export class AppController {  
      constructor() {}  

      @Get()  
      // 注意返回类型中包含`Random`的需求  
      getHello(): Effect.Effect<{ ok: boolean; data: number }, never, Random> {  
        // 注意这里的返回类型是`Effect.Effect<{ ok: boolean; data: number }, never, Random>`  
        return Effect.gen(function* () {  
          const random = yield* Random;  
          // 从`Random`源生成随机数  
          return {  
            ok: true,  
            data: yield* random.next,  
            // 返回一个对象,包含成功标志`ok`和从`random.next`获取的数值`data`  
          };  
        });  
      }  
    }

如果我们现在就这样运行这个效果,会出现一个 Nest JS 控制台上的错误:

错误信息:找不到服务:MyRandomService

那么使用_NestJS_是如何提供功能的呢?这种方式和使用无副作用的服务是否完全一样呢?

我们需要为 NestJS 提供一个使用我们服务的提供者

    // random.service.ts  

    @Injectable()  
    // 服务标记/接口  
    export class Random extends Context.Tag('MyRandomService')<  
      Random,  
      { readonly next: Effect.Effect<number> }  
    >() {}  

    // 实现服务  
    export const RandomLive = Layer.succeed(  
      Random,  
      Random.of({ next: Effect.succeed(Math.random()) }),  
    );
    // app.module.ts

    @Module({
      imports: [
        EffectModule.forRoot({
          // autoServiceDiscovery 需要设为 `true`,才能使用 NestJS 的内建 DI
          // 来为 Effect 服务注入
          autoServiceDiscovery: true,
        }),
      ],
      controllers: [AppController],
      providers: [
        {
          provide: Random, // 提供 Context.Tag 作为标记
          useValue: RandomLive, // 使用 Layer 实现 Context.Tag 的功能
        },
        {
          provide: APP_INTERCEPTOR,
          useClass: EffectRuntimeInterceptor,
        },
      ],
    })
    export class AppModule {}

如果我们现在再访问这个端点一次

    {  
        "ok": true,  
        "信息": 0.2959038884446399  
    }

注意:使用 NestJS 的 DI 并不是提供服务的唯一方法。参见文档 了解更多。

模式验证

一个关键功能是通过一个 NestJS 管道来验证 Effect-Schema。配置过程非常简单——只需在你选择的验证层级(无论是模块、控制器还是方法级别)添加 EffectValidationPipe,然后在控制器中导入你的架构。

// 定义一个用户数据传输对象,包含用户ID和名字。

export class UserDTO extends Schema.Class<UserDTO>('UserDTO')({  
  id: Schema.Number,  
  name: Schema.NonEmptyString,  
}) {}
    // user.controller.ts

    @Controller('user')
    @UsePipes(EffectValidationPipe)
    export class UserController {
      constructor() {}

      @Post()
      addUser(@Body() dto: UserDTO) {
        // 注释
      }
    }

当向API端点发出请求时,请求中的数据会先经过验证,只有在验证成功后才会被接收并传递给函数处理。

默认,验证失败会返回一个通用错误信息。

    {  
        "message": "验证失败",  
        "error": "错误请求",  
        "statusCode": 400  
    }

为了自定义错误信息,你可以使用 EffectModule 中的 customError 选项。这需要创建一个能够接收 ParseError 参数的自定义错误类,该参数会自动传递给你的自定义错误处理程序。

    // user.error.ts  

    import { HttpException } from '@nestjs/common';  
    import { ParseError } from 'effect/ParseResult';  

    // 您的自定义错误需要是一个类,可以接收一个类型为 ParseError 的错误  
    // 这个错误会被自动传递给您的自定义错误  
    export class UserValidationError extends HttpException {  
      constructor(error: ParseError) {  
        super('用户验证失败', 400);  
      }  
    }
    // app.module.ts

    @Module({
      imports: [
        EffectModule.forRoot({ // 效果模块的初始化配置
          validation: {
            customError: UserValidationError, // 用户验证错误
          },
        }),
      ],
      controllers: [UserController], // 控制器
      providers: [], // 提供者
    })
    export class AppModule {}

现在,如果出错,它会返回

{
    "statusCode": 400,
    "message": "用户验证失败"
}

另外,可以通过开启 strict 选项来强制仅使用 Effect Schema,拒绝任何无法验证的值。这种拒绝可能是因为没有提供有效的 Effect Schema,或者是因为验证失败。当启用严格模式时,在控制器中使用普通的 TypeScript 类型而非 Effect Schema 类型将会触发验证错误。

    // app.module.ts

    @Module({
      imports: [
        EffectModule.forRoot({
          validation: {
            customError: UserValidationError,
            strict: true
          },
        }),
      ],
      controllers: [UserController],
      providers: [],
    })
    export class AppModule {}
    // user.controller.ts

    @Controller('user')  
    @UsePipes(EffectValidationPipe)  
    export class UserController {  
      constructor() {}  

      @Post()  
      addUser(@Body() dto: { id: number; name: string }) {  
        //  
      }  
    }

这是一个用户控制器类,用于处理用户相关的请求。它使用了@Controller装饰器来定义控制器处理的路径,@UsePipes装饰器来应用数据验证管道EffectValidationPipe,以及@Post装饰器来定义处理POST请求的方法。addUser方法接受一个包含用户ID和名称的对象dto作为参数。

返回

{
    "statusCode": 400,  
    "message": "用户验证失败"
}

因为我们没有给 Body 提供效果模式,而是提供了一个普通的 TS 类型,而是采用了严格的 TS 模式。

最终的话语

这个库是我个人的一个项目,源于我在这些技术中的实际经验。它还处于初级阶段,目前还不适合用于生产环境,但这是尝试将这两个优秀的框架和谐结合的一个努力。

如果你能试用一下就太好了,遇到问题时标出来,并分享你的改进建议!你的反馈将帮助我们更好地开发它。

仓库:https://github.com/nestjs-effect/nestjs-effect

npm包:https://www.npmjs.com/package/@nestjs-effect/core

我的上一篇文章:关于NestJS的效果 https://medium.com/@yatogamii/effect-with-nestjs-3ee4a4da54f3

这里有一些资源
  • [Effect (Effect)] 文档
  • [Nest (Nest)] 文档
联系

如果你遇到任何问题或 bug,在评论区留言告诉我。

你也可以用这些方式联系我。

  • 领英
  • 邮箱 bracaval.elias.pro@gmail.com

    [MCP]:模型上下文协议
    [LLM]:大型语言模型
    [RAG]:检索增强生成技术
    [SSE]:服务器发送事件

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消