🦄 2024 独立开发者训练营,一起创业!查看介绍 / 立即报名(剩余11个优惠名额) →

博客

Nest.js:Serialization(文档)

Serializer 提供了在返回响应之前的数据处理功能。比如像用户密码这种敏感数据不应该包含在响应里。一些属性可能需要转换一下。响应的实体数据可以只包含指定的属性,比如 id 还有 name。

Nest 提供的 ClassSerializerInterceptor 可以帮我们做这些事情,它用了 class-transformer 包提供的功能。ClassSerializerInterceptor 拿到方法返回的值以后会交给 class-transformer 包里提供的 classToPlain 方法。

排除属性

比如在实体里排除 password 属性:

import { Exclude } from 'class-transformer';

export class UserEntity {
  id: number;
  firstName: string;
  lastName: string;

  @Exclude()
  password: string;
}

使用:

Nest.js:测试(文档)

自动化测试是软件开发的基础,至少测试要覆盖到系统里的一些比较敏感的部分。我们需要使用不同类型的测试,比如集成测试、单元测试、e2e 测试等等,Nest 提供了一些工具可以改善创建这些测试的体验,默认集成了 Jest 测试框架,你也可以使用自己熟悉的测试框架。

安装

先得安装需要的包:

npm install @nestjs/testing --save-dev

单元测试

Unit testing,单元测试。Jest 是一个非常成熟的测试框架,框架可以用来运行测试,里面也提供了 assert 函数,测试替身,可以用来 mocking 或 spying 等等。

假设应用里有两个类:CatsController 与 CatsService。下面我们手工强制让调用 catsService.findAll() 方法的时候返回 result,这样我们就可以测试 catsController.findAll() 方法是否可以返回我们期望的结果了。

Nest.js:自定义 Provider(文档)

很多时候我们需要直接往 Nest 的 Ioc(Inversion of control)  容器里绑定点东西。比如,一些 constant 值,基于当前环境创建的配置对象,外部库,或者根据一些其它定义的 provider 提前算好的值等等。而且你还可以覆盖实施,比如使用不同的类,需要时还可以使用各种测试替身。

要注意一件非常重要的事情,就是 Nest 会使用 token 来确定依赖。一般这个自动生成的 token 就是类。如果你要创建自定义的 provider,你得自个儿选择一个 token。大部分情况这个 token 都可以使用字符串或 symbol 表示。最好你可以在单独的文件里存储这些 token,比如放在一个 constants.ts 文件里。下面是一些可用的选项。

使用值

定义 constant 值,把外部库放到 Nest 容器里,或者使用 mock 对象替换真实的实施,这些情况都可以用 useValue 这种用法。

TypeScript:理解 Reflect Metadata

在定义类或者类方法的时候,可以设置一些元数据,我们可以获取到在类与类方法上添加的元数据,用的方法就是 Reflect Metadata。元数据指的是描述东西时用的数据。

在 TypeScript 里使用 Reflect Metadata 需要做下面这样的配置:

{
  "compilerOptions": {
    "experimentalDecorators": true ,
    "emitDecoratorMetadata": true
  },
}

然后在项目里安装 reflect-metadata 这个包:

npm install reflect-metadata --save

然后做个实验:

JavaScript:理解属性描述器(Property Descriptor)

一个 JavaScript 对象里面可能有一堆属性,属性都有一个名字,还有对应的值,除了这些其实还隐含了一些东西,这就是 Property Descriptor。来做个实验:

const user = {
  name: 'ninghao',
};

const descriptor = Object.getOwnPropertyDescriptor(user, 'name');

console.log(descriptor);

上面定义了一个叫 user 的对象,里面只有一个属性叫 name,对应的值是个字符串 ninghao。如果要检查一下 name 这个属性的 Descriptor,可以使用 Object 上的 getOwnProperyDescriptor 方法,把对象还有对象的属性交给这个方法就可以了。

执行上面的代码,会返回:

TypeScript:理解 Decorator 装饰器

Decorator 装饰器,在 TypeScript 里装饰器就是函数,装饰器可以装饰类,类的属性、方法还有方法的参数等等。装饰器可以处理它装饰的东西,比如给它装饰的东西添加点额外的东西或者修改或替换它装饰的东西。在 Nest.js 应用框架里大量地使用了装饰器。

定义类装饰器

类装饰器就是装饰类用的装饰器,这种装饰器接收一个构造方法参数。

function log(target: any) {
  console.log('hello ~', target);
}

log 其实就是一个函数,只不过根据装饰器要装饰的东西的不同,装饰器函数接收的参数会有一些不同。比如我们这个 log 要装饰类,也就是它是一个类装饰器,那它接收的这个 target 参数就是类的构造方法。log 目前的作用就是在代码运行的时候输出一个 hello,后面加上它接收的 target 参数的值。

新课:Netflix 原创剧里出现的应用框架(Nest.js)

Nest.js 是一款服务端应用框架,你可以用它创建企业级应用(加上 “企业” 显得高级一些 :)。我非常喜欢这款框架,决定再深入研究一下,最终会为你提供一套完整的服务端应用开发的工具、方法与流程。

Nest.js 是基于 Node.js 创建的,Node.js 是一种 JavaScript 语言的运行环境,在服务器上安装一个 Node.js,就可以去运行用 JavaScript  语言写的程序了。也就是用 Nest.js 创建应用,用的语言就是 JavaScript,不过我们用的是带 “外挂” 版本的 JavaScript,也就是 TypeScript。

早先 JavaScript 语言一般会在浏览器上运行,网页上多少都会嵌入点用 JavaScript 语言写的脚本,它是网页界面的组成部分。这些脚本主要是去处理网页界面上发生的一些事情,就是给网页添加点交互功能。

NNC D16:文件上传

D16 要去实现文件上传的功能,在应用的数据库里需要存储用户上传的文件相关的信息。使用 FileInterceptor 这个拦截器可以处理请求里的文件。用 UploadedFile 这个装饰器可以得到上传的文件相关的数据。

  @Post()
  @UseInterceptors(FileInterceptor('file'))
  async store(
    @UploadedFile() data: FileDto
  ) {
    return await this.fileService.store(data);
  }

在客户端上传文件的时候,请求应该设置成 Multipart form,里面添加一个 file 字段,它的值就是要上传的文件。给 FileInterceptor 拦截器提供的参数值是 file ,所以上传的时候就需要包含一个叫 file 的字段 。

相关的配置:

NNC D15:权限控制

D15 一起实现一个简单的权限控制功能,可以要求发出请求的用户必须拥有某个用户角色,或者用户是当前请求的资源的拥有者,满足这些条件的时候应用才会把用户请求的资源返回到客户端。

用户角色可以是一种实体,我们可以先创建一个模块来处理这种实体资源。然后在这个实体里去定义角色与用户这两种实体之间的关系。

@Entity()
export class Role {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'enum', enum: UserRole, unique: true })
  name: UserRole;

  @Column()
  alias: string;

  @ManyToMany(type => User, user => user.roles)
  users: User[]
}

用户实体中的关系:

NNC D14:排序与分页

D14 去实现的内容列表的排序与分页功能。在用 TypeOrm 提供的方法查询出内容列表的时候,查询用的方法可以先去创建一个 QueryBuilder,然后用 take 方法设置一下每次返回的列表项目数量,用 skip 可以设置跳过的项目数量。

    queryBuilder
      .take(limit)
      .skip(limit * (page - 1));

这种分页内容的方法需要两个变量,一个是每页显示的列表数量,还有一个是当前的页码。这两个变量可以动态得到值,比如它们可以来自地址查询符。在 Nest.js 应用里,可以创建一个自定义的参数装饰器,去获取到请求地址里的查询参数的值。

export const ListOptions = createParamDecorator((data: Partial<ListOptionsInterface> = {}, req) => {
  let { page, limit } = req.query;
  ...
}

分页内容还有一个关键是得到总共的结果数量,使用 QueryBuilder 上的 getManyAndCount 这个方法可以返回查询结果还有结果数量。

微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

15260
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点