Skip to content

Latest commit

 

History

History
247 lines (195 loc) · 7.41 KB

README.zh-CN.md

File metadata and controls

247 lines (195 loc) · 7.41 KB

coa-http

GitHub license npm version npm downloads PRs Welcome

English | 简体中文

一个简单、快速、轻量的 HTTP 服务框架,专为 API 而生

特性

  • API 而生 专为 API 开发使用,无需考虑复杂的页面数据渲染逻辑
  • 轻量极简 不到 10K、不依赖第三方库、不过度封装
  • 模式灵活 支持微服务、Serverless 模式、Context 可自由扩展
  • 文档友好 自动生成接口文档、自动生成前端接口代码
  • TypeScript 全部使用 TypeScript 编写,类型约束、IDE 友好
  • Deno 支持在 Deno 下运行(todo)

参考

  • koa 启发,完善 Context 生成机制
  • koa-router 启发,完善路由生成机制
  • koa-bodyparser 启发,完善请求体处理机制
  • egg 启发,完善 Context 扩展机制
  • swagger-ui 为基础,完成接口文档的自动生成

迭代

  • 第一版 coajs:于 2019 年发布的第一个版本,本身属于第三方类库的整合。从多个线上项目中抽离出来,以方便部署更新为目的作为单独的库。随着不断迭代,添加的东西越来越多,coajs变得越来越臃肿,已经不适合轻量级小项目使用。迭代 114 个版本后停止维护

  • 第二版 coa-serve:针对第一版出现的臃肿问题,基于coajs将其化整为零,分别将基础组件和核心组件抽离为单独的库,并将其开源,同时对文档生成机制、路由检索、系统环境配置等机制做了很多的优化。目前已经稳定,线上所有的coajs项目均已经迁移到coa-serve

  • 第三版 coa-http:也就是目前的版本。随着不断迭代,接口对外提供服务的方式已经不限于http了,将tcpwebsocket等服务直接整合到coa-serve中并不优雅。此外,随着笔者的认知进步koa全家桶也并不是最优的选择。故计划将coa-serve拆解,分别重构为 coa-httpcoa-tcpcoa-websocket 等。本项目coa-http正是这三者之一,目前仍在公测阶段

快速开始

环境安装

请确保在操作系统上安装了最新稳定版的 Node.js

新建项目

mkdir <project-name>
cd <project-name>

yarn add coa-http
yarn add typescript tsc-watch @types/node -D

创建文件

gateway            # 网关层
├─ index.ts        # 网关入口
├─ debug           # debug模块
│  └─ test.ts      # debug模块的路由
service            # 服务层
├─ index.ts        # 具体服务的实现
package.json
tsconfig.json

gateway/index.ts 中写入代码

import { CoaContext, CoaHttp } from 'coa-http'

export const http = new CoaHttp(CoaContext)

http.start().then(() => {
  // 做一些启动后的事情
})

gateway/debug/test.ts 中写入代码

import { http } from '..'

http.router.register('调试', {
  '/debug/test/hello': {
    options: {
      method: 'GET',
      name: '你好世界',
    },
    async handler() {
      return { result: 'hello,world!' }
    },
  },
})

tsconfig.json 中写入配置

{
  "compilerOptions": {
    "strict": true,
    "module": "CommonJS",
    "target": "ESNext",
    "baseUrl": ".",
    "outDir": "node_run",
    "sourceMap": true
  },
  "include": ["gateway", "service"]
}

package.json 文件的 scripts 节点中加入 dev

{
  "scripts": {
    "dev": "HOST=3000 NODE_PATH=node_run tsc-watch --onSuccess 'node node_run/gateway'"
  }
}

启动

yarn dev

看到类似下面的运行结果,说明启动成功。修改代码后,会自动重启服务。

Found 0 errors. Watching for file changes.
[server] Booting...
[server] Startup successful in: 5.399953 ms
[server] Listening on: http://localhost:3000/gw/doc

此时,在浏览器中打开 http://localhost:3000/gw/doc,可以直接查看接口文档。

路由

基本用法

使用 http.router.register 方法注册路由,一个最简单的路由如下所示。

http.router.register('调试', {
  '/debug/test/hello': {
    options: {
      name: '测试', // 名称
      method: 'GET', // 调用方法
      param: {
        title: { required: true, description: '标题参数', example: 'test' },
      },
    },
    async handler(ctx) {
      // 获取所有的query参数
      const query = ctx.request.query
      // 获取title参数
      const title2 = ctx.get('title')
      // 使用json的格式返回结果
      return { query, title }
    },
  },
})

路由分组

每注册一批路由,会自动划分为一组。在业务开发时,可以将每个模块拆分为文件单独分组。

// gateway/module-a.ts
http.router.register('A模块', {
  '/api/module-a/action-1': {
    /* ... */
  },
  '/api/module-a/action-2': {
    /* ... */
  },
})
// gateway/module-b.ts
http.router.register('B模块', {
  '/api/module-b/action-1': {
    /* ... */
  },
  '/api/module-b/action-2': {
    /* ... */
  },
  '/api/module-b/action-3': {
    /* ... */
  },
})

Context 上下文

koa 类似,handler 方法包含一个 ctx 参数。ctx 是一个 Context 的实例,包含当前请求过程中上下文所有信息。

http.router.register('调试', {
  '/debug/test/hello': {
    options: {
      method: 'GET',
      name: '你好世界',
    },
    async handler(ctx) {
      // ctx 包含所有上下文信息
      return { result: 'hello, world!' }
    },
  },
})

自定义响应格式

coa-http 原生支持 jsontext 格式的响应结果。但有时候我们需要自定义响应格式,比如流的形式。下面的例子展示了将网络上的资源通过流的形式直接返回。

http.router.register('调试', {
  '/debug/test/proxy': {
    options: {
      method: 'GET',
      name: '流的形式返回结果',
      param: {
        url: { required: true, description: '网络资源路径', example: 'http://github.com' },
      },
    },
    async handler(ctx) {
      // 获取url参数
      const url = ctx.required('url', '')

      // 获取网络上的资源流
      const { data, status, headers } = await axios.get(url, { responseType: 'stream' }).catch((e) => e.response)

      // 设置响应信息
      ctx.res.statusCode = status
      ctx.res.setHeader('Content-Type', headers['content-type'])

      // 网络上的资源流通过管道方式流入响应流
      data.pipe(ctx.res)

      // 自定义响应结果,coa-http将不会进行后续的响应处理
      return ctx.custom()
    },
  },
})