简介
安装
可以使用 Nest CLI
创建项目,也可以克隆一个项目(两者的结果是一样的)。
使用 Nest CLI
构建项目
$ npm i -g @nestjs/cli
$ nest new project-name
其他安装方式
使用 Git
安装基于 TypeScript
的项目
$ git clone https://github.com/nestjs/typescript-starter.git project
$ cd project
$ npm install
$ npm run start
要安装基于 JavaScript
的项目,执行上面的命令时使用 javascript-starter.git
还可以通过 npm
、yarn
安装核心和支撑文件,这种情况下,你将自己创建项目样板文件。
$ npm i --save @nestjs/core @nestjs/common rxjs reflect-metadata
概述
第一步
新建
$ npm i -g @nestjs/cli
$ nest new project-name
src/
目录几个核心文件。
app.controller.spec.ts
app.controller.ts
app.module.ts
app.service.ts
main.ts
app.controller.ts |
具有单一路由的基本控制器。 |
app.controller.spec.ts |
单元测试控制器。 |
app.module.ts |
应用程序的根模块。 |
app.service.ts |
具有单一方法的基本服务。 |
main.ts |
应用程序的入口文件,它使用核心NestFactory 类创建Nest 应用程序的实例。 |
import {
NestFactory } from '@nestjs/core';
import {
AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
默认情况下,发生任何错误,应用程序将以错误码1退出。如果想让它抛出一个错误,禁用
abortOnError
选项,如NestFactory.create( AppModule, {abortOnError: false} )
平台
两种平台开箱即用express
、fastify
platform-express |
Express 一个著名的极简web框架。默认使用@nestjs/platform-express |
platform-fastify |
Fastify 一个高性能和低开销的框架,高度关注提供最大的效率和速度。 |
无论哪个平台,都公开自己的接口。分别被视为NestExpressApplication
和NestFastifyApplication
将一个类型传递给NestFactory.create()
,应用程序对象将有该平台的方法。除非要访问平台API
,否则不用指定类型。
const app = await NestFactory.create<NestExpressApplication>(AppModule);
控制器
控制器处理传入请求并向客户端返回响应。
创建有内置验证的CRUD
控制器
$ nest g resource [name]
路由
@Controller()
装饰器是定义控制器所必需的。在@Controller()
装饰器中指定路径前缀cats
可对一组相关路由分组。
//cats.controller.ts
import {
Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
使用CLI
创建控制器
$ nest g controller cats
@Get()
装饰器,装饰请求处理方法。
该方法返回200
状态码和响应, 介绍两种不同响应:
Standard (recommended)标准(推荐) | 使用这个内置方法,请求返回对象或数组时,自动序列化为JSON 。返回基本类型(如,字符串,数字,布尔值)时只发送值不尝试序列化它。响应状态码默认是200 ,除了使用201 的POST 请求。添加@HttpCode(…) 装饰器,可以改变状态码。 |
Library-specific 特定库 |
使用特定库(如Express )的响应对象,它可以使用@Res() 装饰器注入(如,findAll(@Res() response) )。使用类似response.status(200).send() 的响应。 |
Nest
检测使用@Res()
或@Next()
。同时使用两种方法,则标准方法将对这条路由自动禁用,不再像预期那样工作。要同时使用两种方法(如,通过注入响应对象只设置cookies/headers
,其余工作留给框架),必须在@Res({ passthrough: true })
装饰器中将passthrough
设置为true
。
请求对象
Nest
提供了对底层平台(默认为Express
)请求对象的访问。添加@Req()
装饰器注入请求对象,从而访问请求对象。
//cats.controller.ts
import {
Controller, Get, Req } from '@nestjs/common';
import {
Request } from 'express';
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request): string {
return 'This action returns all cats';
}
}
安装@types/express
便于类型提示。
请求对象有查询字符串、参数、HTTP
头和主体等属性。使用专用的装饰器,如@Body()
或@Query()
,它们是开箱即用的。下面是装饰器和它们代表的对象列表。
@Request(), @Req() |
req |
@Response(), @Res() ***** |
res |
@Next() |
next |
@Session() |
req.session |
@Param(key?: string) |
req.params / req.params[key] |
@Body(key?: string) |
req.body / req.body[key] |
@Query(key?: string) |
req.query / req.query[key] |
@Headers(name?: string) |
req.headers / req.headers[name] |
@Ip() |
req.ip |
@HostParam() |
req.hosts |
注入@Res()
或@Response()
时,Nest
变成Library-specific
模式,您将负责管理响应。必须调用响应对象(如res.json(…)
或res.send(…)
)发出相应类型的响应,否则HTTP
服务器将挂起。
资源
创建POST
处理程序:
//cats.controller.ts
import {
Controller, Get, Post } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Post()
create(): string {
return 'This action adds a new cat';
}
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
Nest
为标准HTTP
方法提供装饰器: @Get()
, @Post()
, @Put()
, @Delete()
, @Patch()
, @Options()
和@Head()
。此外,@All()
定义一个端点处理所有这些。
路由通配符
支持基于模式的路由。如,星号用作通配符,匹配任何字符。
@Get('ab*cd')
findAll() {
return 'This route uses a wildcard';
}
'ab*cd'
路由路径将匹配abcd
, ab_cd
, abecd
等。字符?
, +
, *
和()
可以在路由路径中使用,它们对应正则表达式的子集。
状态码
响应状态码默认是200
, POST
请求除外,它是201
。在处理程序级别添加@HttpCode(…)
装饰器可改变状态码
import HttpCode from '@nestjs/common'
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
状态码不是静态的,而取决于各种因素。在这种情况下,您可以使用library-specific
的响应对象(@Res()
注入),或在发生错误时抛出异常。
头
自定义响应头,使用@Header()
装饰器或特定库(library-specific
)的响应对象(调用res.header()
)。
import Header from '@nestjs/common'
@Post()
@Header('Cache-Control', 'none')
create() {
return 'This action adds a new cat';
}
重定向
将响应重定向到特定URL
,使用@Redirect()
装饰器或特定库(library-specific
)的响应对象(调用res.redirect()
)。
@Redirect()
有两个参数,url
和statusCode
,都是可选的。如果省略,statusCode
的默认值是302
。
@Get()
@Redirect('https://nestjs.com', 301)
动态确定HTTP
状态码或重定向URL
。通过路由控制方法返回特定对象实现:
{
"url": string,
"statusCode": number
}
@Redirect()
装饰器参数被返回值覆盖。例如:
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
return {
url: 'https://docs.nestjs.com/v5/' };
}
}
路由参数
路由参数使用@Param()
装饰器访问。
import Param from '@nestjs/common'
@Get(':id')
findOne(@Param() params): string {
console.log(params.id);
return `This action returns a #${
params.id} cat`;
}
参数传递给@Param()
装饰器,通过名称使用参数。
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns a #${
id} cat`;
}
子域路由
@Controller
装饰器传入含host
属性对象,请求需匹配特定值。
@Controller({
host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
Fastify
缺乏对嵌套路由器的支持,使用子域路由时,应使用(默认)Express
适配器。
host
选项可以使用标记捕获主机名中该位置的动态值。使用@HostParam()
装饰器访问主机参数。
@Controller({
host: ':account.example.com' })
export class AccountController {
@Get()
getInfo(@HostParam('account') account: string) {
return account;
}
}
作用域
几乎所有内容共享。数据库连接池,全局状态单例服务等。Node.js
不遵循请求/响应多线程无状态模型,每个请求由单独线程处理。
某些情况下,控制器基于请求的生命周期是所需的行为,如GraphQL
应用程序中请求缓存、请求跟踪或多租户。
异步性
async
返回Promise
//cats.controller.ts
@Get()
async findAll(): Promise<any[]> {
return [];
}
Nest
路由处理程序甚至更强大,它能够返回RxJS
可观察流(observable streams
)。Nest
自动订阅底层的源并接受最后发出的值(一旦流完成)。
//cats.controller.ts
@Get()
findAll(): Observable<any[]> {
return of([]);
}
请求有效载荷
添加@Body()
装饰器。
使用TypeScript
,需要确定DTO
(数据传输对象)。
//create-cat.dto.ts
export class CreateCatDto {
name: string;
age: number;
breed: string;
}
//cats.controller.ts
@Post()
async create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
ValidationPipe
可以过滤掉不该被接收的属性。将可接受的属性列入白名单,没有在白名单中的属性将从结果对象中删除。在CreateCatDto
示例中,白名单是名称、年龄和品种属性。
完整的资源示例
//cats.controller.ts
import {
Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import {
CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${
query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${
id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${
id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${
id} cat`;
}
}
特定库方法
讨论了Nest
操作响应的标准方式。操作响应的第二种方式是使用特定库(library-specific
)的响应对象。注入特定的响应对象,使用@Res()
装饰器。
import {
Controller, Get, Post, Res, HttpStatus } from '@nestjs/common';
import {
Response } from 'express';
@Controller('cats')
export class CatsController {
@Post()
create(@Res() res: Response) {
res.status(HttpStatus.CREATED).send();
}
@Get()
findAll(@Res() res: Response) {
res.status(HttpStatus.OK).json([]);
}
}
对响应对象完全控制(头操作、特定库的特性等)。缺点,代码依赖指定库(响应对象api
不同),难测试(模拟响应对象等)。
失去与Nest
特性(依赖于Nest
标准响应)的兼容性,如Interceptors
(拦截器)和@HttpCode() / @Header()
装饰器。解决这个问题,设置passthrough
为true
@Get()
findAll(@Res({
passthrough: true }) res: Response) {
res.status(HttpStatus.OK);
return [];
}
现在根据条件设置cookies
或headers
,其余工作留给框架。
提供者
提供者是基本概念。许多基本类被视为提供者——服务(services
)、存储库(repositories
)、工厂(factories
)、助手(helpers
)等。提供者主要思想是作为依赖注入; 意味着对象之间可以创建各种关系,“连接”对象实例可以委托给运行系统。
构建的CatsController
。控制器处理HTTP
请求,复杂的任务委派给提供者。提供者是声明为提供者的普通类。
服务
//cats.service.ts
import {
Injectable } from '@nestjs/common';
import {
Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
@Injectable()
装饰器附加了元数据(metadata
),声明CatsService
是个由Nest IoC
容器管理的类。
//interfaces/cat.interface.ts
export interface Cat {
name: string;
age: number;
breed: string;
}
//cats.controller.ts
import {
Controller, Get, Post, Body } from '@nestjs/common';
import {
CreateCatDto } from './dto/create-cat.dto';
import {
CatsService } from './cats.service';
import {
Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {
}
@Post()
async create(