一. 前言
第一篇文章我们实现了手动搭建出一个极简的Nest服务器,但这是结束也即是开端!
停下来想一下,我们现在既然已经有了最最重要的服务器,那么我们现在需要什么?
对了,当然是写接口,服务器服务器嘛,不就是玩数据的嘛
那么问题来了, 如果我目前想实现一个接口都需要什么步骤呢?
举个栗子
我目前想在浏览器中输入localhost:3000/helle/create 然后页面得到'hello nest'
因为Nestjs的底层就是封装的express,所以我们直接拿express来解决一下这个问题
如果用过express的同学可能会知道,express来定义路由与返回数据的方式如下:
const app = express()
app.get('/hello/create', (req, res, next => {
res.send('hello nest')
}))
非常通俗易懂对吧,虽然但是,我们还是需要来拆解一下这段代码都干了些什么,因为这对我们后面写各种装饰器有莫大的帮助
const app = express()
app.get('/hello/create', (req, res, next => { res.send('hello nest') }))
/**
* 1.app.get() 表示该请求方式为GET
* 2.app.get('/hello/create') 请求路由
* 3.(req, res, next => { res.send('hello nest') }) req: 请求参数, res: 返回体, next:中间件
*/
分析这段express之后,得到了3个关键的信息,请求方式 / 路由路径 / 请求参数与返回值
☆在Nest中,一个控制器(Controller)代表着一个单独的模块,可以通过控制器装饰器来设置统一的请求前缀
而且在Nest,它并没有用这种方式来定义一个请求,而是使用各种封装后的装饰器来实现,比如:
- @Controller('/hello') => Nest中可以通过控制器装饰器来设置统一的路由前缀
- @Get('/create') => 可以使用参数装饰器来配置该接口的路由路径
二. 完善模块装饰器 @Module
// 类装饰器(模块装饰器)
// 导入元数据包
import 'reflect-metadata'
interface ModuleMetadata {
controllers: Function[]
}
/**
* @param metadata 类的数组
* @returns 类装饰器(模块装饰器)
*/
export const Module = (metadata: ModuleMetadata): ClassDecorator => {
// 给模块类添加元数据, target是AppModule或其他模块类, 元数据的名字叫controllers, 值是controllers数组: controllers: [AppController]
return (target: Function) => {
console.log(target)
Reflect.defineMetadata('controllers', metadata.controllers, target)
}
}
三. 控制器装饰器 @Controller
// 控制器装饰器
// 导入元数据包
import 'reflect-metadata'
interface ControllerOptions {
prefix?: string
}
// 控制器参数重载
export function Controller(): ClassDecorator // 传入空字符串
export function Controller(prefix: string): ClassDecorator // 传入字符串
export function Controller(options: ControllerOptions): ClassDecorator // 传入对象
export function Controller(prefixOrOptions?: string | ControllerOptions): ClassDecorator {
let options: ControllerOptions = {}
if (typeof prefixOrOptions === 'string') options.prefix = prefixOrOptions
if (typeof prefixOrOptions === 'object') options = prefixOrOptions
return (target: Function) => {
// 给控制器类添加prefix这个代表路径前缀的属性的元数据
Reflect.defineMetadata('prefix', options.prefix || '', target)
}
}
四. 参数装饰器 @GET @Post @Put @Patch @Delete
// 参数装饰器, GET, POST, BODY, DELETE, PATCH, PUT
// 导入元数据包
import 'reflect-metadata'
/**
* @param target 类的原型: AppController.prototype
* @param propertyKey 方法名: hello
* @param desciprtor 属性描述器: 表示hello方法的属性描述器
*/
export const Get = (path: string = ''): MethodDecorator => {
return (target: any, propertyKey: string, desciprtor: PropertyDescriptor) => {
// 为desciprtor.value,也就是hello函数添加元数据path
Reflect.defineMetadata('path', path, desciprtor.value)
// 为desciprtor.value,也就是hello函数添加元数据method
Reflect.defineMetadata('method', 'GET', desciprtor.value)
}
}
使用模块装饰器
import { Module } from './@nestjs/common/module.decorator'
import { AppController } from './app.controller'
@Module({
controllers: [AppController]
})
export class AppModule {}
使用控制器装饰器与参数装饰器
import { Controller } from './@nestjs/common/controller.decorator'
import { Get } from './@nestjs/common/httpMethod.decorator'
@Controller()
export class AppController {
@Get('hello')
hello(): string {
return 'hello'
}
}