0.6.5 • Published 2 years ago

http-yyds v0.6.5

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

http-yyds

一个注解风格的 TypeScript HTTP Server。适用于封装 API 或个人小项目。目前还未到 1.0.0 版本,切勿用在生产环境。

安装

npm install http-yyds

项目配置

因为使用了装饰器和元数据反射,需要在 tsconfig.json 中加入以下开启以下配置项:

{
    "compilerOptions": {
        "target": "es2021",
        "module": "esnext",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "moduleResolution": "node"
    }
}

示例

import { App } from "http-yyds";

let app = new App("127.0.0.1", 8080);

class Test {
    @app.get("/hello")
    hello(name: string) {
        return `Hello ${name}!`;
    }

    @app.get("/person/{name}/sex")
    getCurTime(name: string) {
        if (name == "xiaoming") {
            return `man`;
        } else if (name == "xiaohong") {
            return "woman";
        } else {
            return "unknown";
        }
    }

    @app.post("/cal/sum")
    sum(a: number, b: number) {
        return `${a}+${b}=${a + b}`;
    }
    
    @app.get("/api/person/{name}/info")
    getPersion(name: string) {
        if (name == "xiaoming") {
            return { sex: "man", name: "xiaoming", age: 18 };
        } else if (name == "xiaohong") {
            return { sex: "woman", name: "xiaohong", age: 19 };
        } else {
            throw new Error(`${name} 的信息不存在`);
        }
    }
}

app.listen();

功能

用注解映射请求路径和响应方法

http-yyds 提供的注解 API 可以根据请求路径和请求方法将请求映射到响应方法,方法可以是同步方法,也可以是异步方法。

例如,下面将路径 "/hello" 的 GET 请求映射到方法 hello(name:string)

@app.get("/hello")
hello(name: string) {
    return `Hello ${name}!`;
}

还可以将多个请求路径映射到同一个响应方法,只要叠加注解就行:

@app.get("/")
@app.get("/index")
getIndex() {
    // 省略。。。
}

支持 HTTP GET、POST、PUT、DELETE

App 类内置了以下方法注解,用于支持常用的 HTTP 请求方法。

interface App {
    get(path: string);
    post(path: string);
    put(path: string);
    delete(path: string);
}

参数 path 表示请求的路径。

对于没有内置支持的 HTTP 请求方法,未来会提供一个扩展方法 mapping(path: string, method: string) 让用户自定定义方法注解。

自动提取和填充参数

http-yyds 会自动从请求中提取参数,并将参数填充为响应方法中的同名实参。

URL 中的查询参数

例如前面的示例中的代码片段:

@app.get("/hello")
hello(name: string) {
    return `Hello ${name}!`;
}

收到请求时会自动提取请求 URL 中的查询参数:

$ curl http://127.0.0.1:8080/hello?name=xiaoming
hello xiaoming!

路径参数

例如前面的示例中的代码片段:

@app.get("/person/{name}/sex")
getCurTime(name: string) {
    if (name == "xiaoming") {
        return `man`;
    } else if (name == "xiaohong") {
        return "woman";
    } else {
        return "unknown";
    }
}

收到请求后会自动将路径中的 name 参数:

$ curl http://127.0.0.1:8080/person/xiaoming/sex
man
$ curl http://127.0.0.1:8080/person/xiaohong/sex
woman
$ curl http://127.0.0.1:8080/person/xiaohong/sex
woman
$ curl http://127.0.0.1:8080/person/unknown/sex
unknown

POST 请求体中的参数

例如前面的示例中的代码片段:

 @app.post("/cal/sum")
sum(a: number, b: number) {
    return `${a}+${b}=${a + b}`;
}
application/x-www-form-urlencoded 格式的参数
$ curl -d 'a=1&b=2' http://127.0.0.1:8080/cal/sum
1+2=3
application/json 格式的参数
$ curl -H 'Content-Type: application/json'  -d '{"a":1,"b":2}' http://127.0.0.1:8080/cal/sum
1+2=3

自动处理响应函数的返回

http-yyds 会自动将响应方法的返回封装成 HTTP 响应。

将字符串类型的返回转成 text/plain 类型的 HTTP 响应:

@app.get("/person/{name}/sex")
getCurTime(name: string) {
    if (name == "xiaoming") {
        return `man`;
    } else if (name == "xiaohong") {
        return "woman";
    } else {
        return "unknown";
    }
}
$ curl -i http://127.0.0.1:8080/person/xiaohong/sex                             HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Date: Fri, 07 Jan 2022 12:22:44 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

woman

将对象类型的响应转成 application/json 类型的 HTTP 响应:

 @app.get("/api/person/{name}/info")
getPersion(name: string) {
    if (name == "xiaoming") {
        return { sex: "man", name: "xiaoming", age: 18 };
    } else if (name == "xiaohong") {
        return { sex: "woman", name: "xiaohong", age: 19 };
    } else {
        throw new Error(`${name} 的信息不存在`);
    }
}
$ curl -i http://127.0.0.1:8080/api/person/xiaoming/info
HTTP/1.1 200 OK
Content-Type: application/json
Date: Fri, 07 Jan 2022 12:40:15 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

{"sex":"man","name":"xiaoming","age":18}

如果响应函数抛出异常,也能将其转成 500 响应返回:

$ curl -i http://127.0.0.1:8080/api/person/xxx/info
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Date: Fri, 07 Jan 2022 12:40:51 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

{"message":"服务内部出错:Error: xxx 的信息不存在"}

如果自动返回不满足需求,http-yyds 还提供了一个 Response 类用于自定义返回:

例如,下面返回一个 html 文件:

import { App, Response } from "http-yyds";

@app.get("/")
@app.get("/index")
getIndex() {
    return new Response(
        200,
        "OK",
        { "Content-Type": contentType },
        "<h1>Hello World!</h1>"
    );
}

自动处理错误请求

如果请求路径不存在对应的响应方法,则自动返回 404:

$ curl -i http://127.0.0.1:8080/api/xx
HTTP/1.1 404 Not Found
Content-Type: application/json
Date: Fri, 07 Jan 2022 12:45:15 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

{"message":"未找到/api/xx对应的资源"}

如果请求对应的路径存在响应方法,但是不特定 HTTP 请求方法,则自动返回 405 响应:

$ curl -i http://127.0.0.1:8080/cal/sum
HTTP/1.1 405 Method Not Allowed
Allow: POST
Content-Type: application/json
Date: Fri, 07 Jan 2022 12:47:23 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

{"message":"/cal/sum对应的资源不支持GET"}

未来会支持更多类型的自动响应。

todo

  • 完成面向切面的拦截器
  • 提供映射基础路径和处理器类的注解
  • 支持用户自己实例化处理器类

注意

  • 在未发布 1.0.0 版本前,http-yyds 的接口会随着作者的经验和品味变化。
  • http-yyds 基于的装饰器和元数据反射都处于”建议征集的第二阶段“,不知道什么时候出现在正式标准中。
  • 毕竟是个人作品,在发布 1.0.0 之前不要用于生产环境。
0.6.3

2 years ago

0.6.2

2 years ago

0.6.5

2 years ago

0.6.4

2 years ago

0.6.1

2 years ago

0.6.0

2 years ago

0.5.4

2 years ago

0.5.3

2 years ago

0.5.2

2 years ago

0.5.1

2 years ago

0.5.0

2 years ago

0.4.0

2 years ago

0.3.1

3 years ago

0.3.0

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago