提供器 (Provider)
提供器 (provider) 是 Nest 中的一个基本概念。许多基本的 Nest 类可以被视为提供器 - 服务、存储库、工厂、助手等等。而提供器的主要思想是它可以作为依赖注入;这也意味着对象之间可以创建各种关系。
在控制器章节中,我们创建了一个DogsController
类,然而 控制器应该处理 HTTP 请求并将更复杂的任务委托给提供器。提供程序是在module
中声明为providers
的纯 JavaScript 类。
提一嘴:无论你记得与否,强烈建议你遵循SOLID 原则。
*服务 (services)
让我们从搭建一个简单的 DogsService
开始吧。该服务将负责数据存储和检索,并设计为供 DogsController
使用。这说明什么?这说明把DogsService
被定义为提供器是 100% 没问题的~
首先,在dogs 文件夹目录下创建一个名为dogs.service.ts
的文件:
注意: 你同样可以使用CLI 来创建,只需在终端执行nest g service dogs
命令即可。
/* dogs.service.ts */
import { Injectable } from "@nestjs/common";
import { Dog } from "./interfaces/dog.interface";
@Injectable()
export class DogsService {
private readonly dogs: Dog[] = [];
create(dog: Dog) {
this.dogs.push(dog);
}
findAll(): Dog[] {
return this.dogs;
}
}
但是看到第二行就不难从代码中发现,引入的Dog 是什么?这里的Dog 便是我们的Dog 接口( interface )。它看起来可能是这样的:
/* src/dogs/interfaces/dog.interface.ts */
export interface Dog {
name: string;
age: number;
bark: string;
}
不难看出,我们的DogsService
是一个具有一个属性和两个方法的基本类。唯一的新特性是它使用了@Injectable()
装饰器。
那么我们有了一个可以检索狗的服务类了,就在DogsController
中使用它吧:
注意:在这里我们修改了之前dogs.controller.ts
的代码:
/* dogs.controller.ts */
// ...
import { Dog } from "./interfaces/dog.interface";
import { DogsService } from "./dogs.service";
@Controller('dogs')
export class DogsController {
constructor(private dogsService: DogsService) {}
@Post()
async create(@Body() createDogDto: CreateDogDto) {
this.dogsService.create(createDogDto);
}
@Get()
async findAll(): Promise<Dog[]> {
return this.dogsService.findAll();
}
// ...
}
对于上方新增修改的代码:
-
constructor(...) {}
:DogsService
通过类的构造函数来注入 ; -
(private dogsService: DogsService)
:此private
语法的使用允许我们立即在同一位置声明和初始化catsService
成员; -
后续的代码块修改:简单来说,就是我们在
DogsService
内定义了两个方法,分别在POST 和GET 请求里调用使用它们就可以了。 -
其中对于
createDogDto
: 该请求负载在之前并没有发挥作用,如今它的作用来了:它可以携带着对应的请求体去添加新增数据,这也是为什么create-dog.dto.ts
内的类属性与我们的dog.interface.ts
内的属性相同的原因。
目前对于我们学到的注入方式,可以将其称之为:基于构造函数的注入。
提供器的注册 (registration)
现在我们已经有了一个提供器了(DogsService
) ,并且该提供器也有一个消费者(DogsController
) ,接下来要做的就是向Nest 注册该服务,以便它可以执行注入。我们需要做的就是:编辑模块文件(app.module.ts
) 并将服务添加到Module()
装饰器的providers
数组内。
如下:
/* app.module.ts */
// ...
import { DogsService } from './dogs/dogs.service';
@Module({
imports: [],
controllers: [AppController, DogsController],
// 在本注释的下方的providers 数组内添加DogsService
providers: [AppService, DogsService],
})
export class AppModule {}
现在,Nest 就可以解析DogsController
类的依赖了。
此时的目录结构可以给大家展示一下:
然后当我们再次将项目跑起来 (或者你在dev 环境下运行,一直在监视文件变化则无需再次跑起来 )时,来看看对应的效果:
这时候你会发现返回的是一个空数组,因为此时我们没有任何的数据存在里面;那么我们用ApiFox 来往里面存一两条数据试试:
由于我们的代码中只是执行了DogsService
的create()
方法,即 将对应的数据存在了私有的dogs
数组中,在DogsController
类内也没有返回值,故不会返回任何内容。
在这里还要提一嘴的是,POST 请求的payload (请求体 & 请求负载) 在ApiFox 中是放在Body 里的,和我们使用的 @Body()
装饰器 是不是一模一样呢~ 请求体内的参数格式,大家按照我这里的填写就ok~
然后我们再发送一次GET 请求试试:
是不是很有意思?仿佛自己像一个后端程序员一样写了一个接口出来?你仿佛的没错,这就是Nest !恭喜你到此为止,已经掌握了controller
和 provider
的基本使用了!