Web
这节内容将介绍unioc
的后端
部分。虽然叫做@unioc/web
,但是它目前主要还是提供对Node
/Bun
/Deno
等后端环境的适配与支持。它的主要职责是为多种不同的Web请求相关
的框架和协议提供适配器,如Restful
、WebSocket
等。
Restful
@unioc/web
内部提供了一个类扫描器(RestfulScanner
),它实现了IRestfulScanner
接口,并且关联了四个子类,下面将一一介绍。
IRestfulScanner
扫描器,提供一些方法来遍历和管理扫描到的类,还提供了另外一些便捷方法如mergePath
(用来合并@RestController
和方法注解上的@Get
、@Post
等装饰器的路径)等。
类型定义
export interface IRestfulScanner {
/**
* ### Merge the controller path and method path.
*
* 🔍 Merge the controller path and method path.
*
* @param controllerPath - The controller path.
* @param methodPath - The method path.
*/
mergePath(controllerPath: string, methodPath: string): string
/**
* ### Add a new controller wrapper.
*
* 📉 Add a new controller wrapper.
*/
add(controller: IRestControllerWrapper): this
/**
* ### Find all the controller wrappers.
*
* 🚰 Find all the controller wrappers.
*
* @param force - Whether to force the search.
*/
findAll(force?: boolean): IRestControllerWrapper[]
/**
* ### Find all the method operators.
*
* 🚰 Find all the method operators.
*/
findAllMethodOperator(): IRestMethodOperator[]
/**
* ### Resolve all the controller wrappers.
*
* 👌 Resolve all the controller wrappers.
*/
resolveAll(): Promise<this>
/**
* ### Search for the method operator by full path.
*
* 🔍 Search for the method operator by full path.
*
* @param fullPath - The full path. Must start with `/`.
*/
search(fullPath: `/${string}`): IRestMethodOperator[]
/**
* ### Resolve the node handler.
*
* 🐢 Resolve the node handler for the current scanner.
*/
resolveNodeHandler?(): Awaitable<IRestfulNode.Handler>
/**
* ### Resolve the connect handler.
*
* 🔗 Resolve the connect handler for the current scanner.
*/
resolveConnectHandler?(): Awaitable<IRestfulConnect.Handler>
/**
* ### Resolve the context handler.
*
* ⛰️ Resolve the context handler for the current scanner.
*/
resolveContextHandler?(): Awaitable<IRestfulContext.Handler>
/**
* ### Resolve the web standard handler.
*
* 🌐 Resolve the web standard handler for the current scanner.
*/
resolveWebStandardHandler?(): Awaitable<IRestfulWebStandard.Handler>
}
IRestControllerWrapper
控制器wrapper,每个wrapper有一个对应一个核心包的IClassWrapper
用来导航到IoC容器,在这层还可以获取到整体的@RestController
级别的装饰器元数据。比如有如下伪代码:
@RestController('/api')
@RestController('/api2')
class RestController {}
那么定义的两个前缀路由都可以通过getFullControllerOptions
等方法,由这层完整读取。
类型定义
export interface IRestControllerWrapper {
/**
* ### Get the restful scanner.
*
* 🔍 Get the restful scanner.
*/
getRestfulScanner(): IRestfulScanner
/**
* ### Get the class wrapper.
*
* 🔍 Get the class wrapper.
*/
getClassWrapper(): IClassWrapper
/**
* ### Get the current controller options.
*
* ⚙️ Get the current controller options.
*/
getFullControllerOptions(): RestController.Options[]
/**
* ### Get the current method options.
*
* ⚙️ Get the current method options.
*/
getFullMethodOptions(): IHttpMethodMetadata[]
/**
* ### Find all the controller operators.
*
* 🚰 Find all the controller operators.
*
* @param force - Whether to force the search.
*/
findAll(force?: boolean): IRestControllerOperator[]
/**
* ### Add a new controller operator.
*
* 📉 Add a new controller operator.
*/
add(operator: IRestControllerOperator): this
}
IRestControllerOperator
这一层为遍历了IRestControllerWrapper
后获取到的单个@RestController
信息,比如上面的例子:
@RestController('/api')
@RestController('/api2')
class AppController {}
那么这一层将一一读取/api
和/api2
两个路径,并提供便捷方法获取到它们。
类型定义
export interface IRestControllerOperator {
/**
* ### Get the current controller wrapper.
*
* 🔍 Get the current controller wrapper.
*/
getControllerWrapper(): IRestControllerWrapper
/**
* ### Get the current controller path.
*
* 📃 Get the current controller path.
*/
getControllerPath(): string
/**
* ### Get the current controller options.
*
* ⚙️ Get the current controller options.
*/
getFullControllerOptions(): RestController.Options
/**
* ### Find all the method wrappers.
*
* 🚰 Find all the method wrappers.
*
* @param force - Whether to force the search.
*/
findAll(force?: boolean): IRestMethodWrapper[]
/**
* ### Add a new method wrapper.
*
* 📉 Add a new method wrapper.
*/
add(operator: IRestMethodWrapper): this
}
IRestMethodWrapper
方法wrapper,可以获取到当前方法的propertyKey
等,并且提供一些便捷方法获取当前方法的反射信息,如getReturnType
、getParamTypes
等。此外,还提供execute
方法来执行当前方法。
类型定义
export interface IRestMethodWrapper {
/**
* ### Get the current controller operator.
*
* 🔍 Get the current controller operator.
*/
getControllerOperator(): IRestControllerOperator
/**
* ### Get the current property key.
*
* 🌾 Get the current property key.
*/
getPropertyKey(): PropertyKey
/**
* ### Execute the current method.
*
* 📖 Execute the current method.
*/
execute<T, TE>(args: unknown[], extraOptions: Record<string, unknown>): Promise<IResult<T, TE>>
/**
* ### Get the current method's return type.
*
* 😚 Shortcut to get the current method's return type by IMetadataScanner.
*/
getReturnType(): IClass | undefined
/**
* ### Get the current method's param types.
*
* 😚 Shortcut to get the current method's param types by IMetadataScanner.
*/
getParamTypes(): IClass[]
/**
* ### Find all the method operators.
*
* 🚰 Find all the method operators.
*
* @param force - Whether to force the search.
*/
findAll(force?: boolean): IRestMethodOperator[]
/**
* ### Add a new method operator.
*
* 📉 Add a new method operator.
*/
add(operator: IRestMethodOperator): this
}
IRestMethodOperator
方法操作符,获取当前方法的单个路由信息,可以获取到当前方法中,当前注解所设置的httpMethod
、path
等,并且提供一些便捷方法如getFullPath
(帮你自动调用IRestfulScanner.mergePath
合并@RestController
和方法注解上的路径)等。
类型定义
export interface IRestMethodOperator {
/**
* ### Get the current method wrapper.
*
* 🔍 Get the current method wrapper.
*/
getMethodWrapper(): IRestMethodWrapper
/**
* ### Get the current http method.
*
* 🌍 Get the current http method.Get the current http method.
*/
getHttpMethod(): IHttpMethod
/**
* ### Get the current full path.
*
* 🧮 Computed to full path using `mergePath`.
* It will merge the {@linkcode IRestControllerOperator.getControllerPath} and {@linkcode getPath}.
*/
getFullPath(): string
/**
* ### Get the current path.
*
* 📃 Get the current method path.
*/
getPath(): string
/**
* ### Get the current method options.
*
* ⚙️ Get the full current method's options.
*/
getFullMethodOptions(): IHttpMethodMetadata
}
为什么我们需要这么复杂的设计?
上面的设计虽然繁杂,但是能使得任何其他的框架都可以通过@unioc/web
的适配器来实现对unioc
的Restful
功能的支持。
为了尽量保持简单明了我们已经尽了最大的努力,使得甚至几乎每一个人都能快速制作成一些装饰器甚至是实现自己的Web适配器框架,或者当一些性能更好的Web框架出现时,可以快速实现适配,可用性、可扩展性拉满 🚀
对于IoC框架层
可以通过继承这些基实现类,来实现任意Web IoC框架
的适配,如@unioc/adapter-nestjs
:
import type { IRestfulScanner } from 'unioc/web'
import { RestfulScanner } from 'unioc/web'
export class NestJsRestfulScanner extends RestfulScanner implements IRestfulScanner {
// 重写需要重写的方法即可
}
对于Web框架层
通过统一的接口来对整个容器中的所有控制器以及方法进行快捷遍历,如@unioc/web-express
,代码仅仅只有一点点,就做到了对express
框架的适配,因为大部分工作都由@unioc/web
来完成了。