# http-yyds **Repository Path**: shimachao/http-yyds ## Basic Information - **Project Name**: http-yyds - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-10 - **Last Updated**: 2022-01-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # http-yyds 一个注解风格的 TypeScript HTTP Server。适用于封装 API 或个人小项目。目前还未到 1.0.0 版本,切勿用在生产环境。 ## 安装 ```shell npm install http-yyds ``` ## 项目配置 因为使用了装饰器和元数据反射,需要在 `tsconfig.json` 中加入以下开启以下配置项: ```json { "compilerOptions": { "target": "es2021", "module": "esnext", "experimentalDecorators": true, "emitDecoratorMetadata": true, "moduleResolution": "node" } } ``` ## 示例 ```typescript 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)`。 ```typescript @app.get("/hello") hello(name: string) { return `Hello ${name}!`; } ``` 还可以将多个请求路径映射到同一个响应方法,只要叠加注解就行: ```typescript @app.get("/") @app.get("/index") getIndex() { // 省略。。。 } ``` ### 支持 HTTP GET、POST、PUT、DELETE App 类内置了以下方法注解,用于支持常用的 HTTP 请求方法。 ```typescript interface App { get(path: string); post(path: string); put(path: string); delete(path: string); } ``` 参数 `path` 表示请求的路径。 对于没有内置支持的 HTTP 请求方法,未来会提供一个扩展方法 `mapping(path: string, method: string)` 让用户自定定义方法注解。 ### 自动提取和填充参数 http-yyds 会自动从请求中提取参数,并将参数填充为响应方法中的同名实参。 #### URL 中的查询参数 例如前面的示例中的代码片段: ```typescript @app.get("/hello") hello(name: string) { return `Hello ${name}!`; } ``` 收到请求时会自动提取请求 URL 中的查询参数: ```shell $ curl http://127.0.0.1:8080/hello?name=xiaoming hello xiaoming! ``` #### 路径参数 例如前面的示例中的代码片段: ```typescript @app.get("/person/{name}/sex") getCurTime(name: string) { if (name == "xiaoming") { return `man`; } else if (name == "xiaohong") { return "woman"; } else { return "unknown"; } } ``` 收到请求后会自动将路径中的 `name` 参数: ```shell $ 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 请求体中的参数 例如前面的示例中的代码片段: ```typescript @app.post("/cal/sum") sum(a: number, b: number) { return `${a}+${b}=${a + b}`; } ``` ##### `application/x-www-form-urlencoded` 格式的参数 ```shell $ curl -d 'a=1&b=2' http://127.0.0.1:8080/cal/sum 1+2=3 ``` ##### `application/json` 格式的参数 ```shell $ 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 响应: ```typescript @app.get("/person/{name}/sex") getCurTime(name: string) { if (name == "xiaoming") { return `man`; } else if (name == "xiaohong") { return "woman"; } else { return "unknown"; } } ``` ```shell $ 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 响应: ```typescript @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} 的信息不存在`); } } ``` ```shell $ 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 响应返回: ```shell $ 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 文件: ```typescript import { App, Response } from "http-yyds"; @app.get("/") @app.get("/index") getIndex() { return new Response( 200, "OK", { "Content-Type": contentType }, "

Hello World!

" ); } ``` ### 自动处理错误请求 如果请求路径不存在对应的响应方法,则自动返回 404: ```shell $ 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 响应: ```typescript $ 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 之前不要用于生产环境。