README
一个基于 Node.js 的 web 框架
上手
//index.ts
import Server from 'metu/server'
const bootstrap = async () => {
const server = new Server()
await server.create() //创建应用
server.run(80)
}
bootstrap()
它的 Server 与 Koa 非常相似(Context不同),使用洋葱模型和 Promise 编写中间件,如果不调用 create 方法创建应用,你可以理解为它就是另一个 Koa
特性
- TypeScript开发、完善的类型提示以及方法中文注释。
- 自动加载、支持开发/生产环境热更新。
- 非侵入式、框架制定了规范但不制定流程。
- 内置Redis、MySQL、Session等支持,开箱即用。
快速开始
新建您的项目文件夹后安装并创建项目
$ npm install metu
$ npx metu new
运行开发环境,开发环境下会在文件变更时自动重载
$ tsc -w
$ npm run dev
默认监听80端口,浏览器访问:http://127.0.0.1
项目结构
强烈建议您的项目使用 TypeScript 开发。
config/**.json 应用配置、自定义配置
lib TS编译目录
src 应用根目录
src/app 应用目录
src/index.ts 入口文件
src/plugin.ts 插件配置,应用生命周期
src/type.d.ts 自定义类型,覆盖未知类型
package.json Node.js项目配置
tsconfig.json TS编译配置
示例
快速编写一个接口:
//src/app/Home.ts
import { App, Router } from 'metu'
@Router('/home')
export class Demo extends App {
get() {
return 'Hello world'
}
}
浏览器访问:http://127.0.0.1/home 响应:Hello world
自定义匹配路由:
//src/app/Home.ts
import { App, Router } from 'metu'
@Router('/home/:id')
export class Demo extends App {
get() {
const params = this.context.url.params()
return 'Hello ' + params.id[0]
}
}
浏览器访问:http://127.0.0.1/home/12345 响应:Hello 12345
使用验证器:
//src/app/Home.ts
import { App, Router, Validator, Context } from 'metu'
//定义验证器返回参数[]
function getDemo(context: Context){
const params = this.context.url.params()
return [Number(params.id[0])]
}
@Router('/home/:id')
export class Demo extends App {
@Validator(getDemo)
get(id: number) {
return 'Hello ' + id
}
}
浏览器访问:http://127.0.0.1/home/12345 响应:Hello 12345
通常我们将验证码拆分为不同的模块 import 使用
方法可定义五种名称:get/post/put/delete/all
如果定义all方法,所有请求类型都会被触发all,如果all没有返回值,那么会再次调用对应请求方法
MySQL
//src/app/Home.ts
import { App, Router, Mysql } from 'metu'
@Router('/home')
export class Demo extends App {
get() {
const mysql = await Mysql()
const result = mysql.select('*').from('user').limit(0,1).run()
mysql.close()
return result
}
}
浏览器访问:http://127.0.0.1/home 响应JSON:[{ "name: "value" }]
Redis
//src/app/Home.ts
import { App, Router, Redis } from 'metu'
@Router('/home')
export class Demo extends App {
get() {
const scan = await Redis.scan()
return scan.result
}
}
浏览器访问:http://127.0.0.1/home 响应JSON:["key1", "key2"]
插件 or 错误处理
定义 src/plugin.ts 来获取应用的周期控制
//src/plugin.ts
import { Plugin, App } from 'metu'
export default class extends Plugin {
async onError(type: number, error: unknown, app: App | null) {
this.context.statusCode = 200
this.context.body = 'error'
}
async onResponse(value: unknown, app: App) {
this.context.statusCode = 200
this.context.body = value as string
}
}
type 有五种类型:
- 0 (构造错误)
- 1 (验证器错误)
- 2 (方法错误)
- 3 (析构方法错误)
他们的流程从上依次执行,遇到错误均会停止后续调用。
进阶
- 使用基类
定义一个基类基础自
App
管理你应用的用户权限控制,基类很方便的帮助你定义各种API的访问权限
//src/base.ts
import { App, Context } from 'metu'
export class Base extends App {
declare context: Context & {
session: {
userInfo: {
id: number
level: number
}
}
}
constructor(context: Context) {
super(context)
if (!context.session.userInfo) {
throw '请登录账户!' //抛出错误由plugin.ts处理错误输出
}
}
}
- 使用测试器 测试器能在开发环境下 修改文件后/运行后 自动发送一个请求调用目标接口,它可以传递参数
import { App, Context, Router } from 'metu'
@Router('/Tag', {method: 'get'})
export class Tag extends App {
async get() {
return {test: 123}
}
}