# TCB Express-Like Router

利用腾讯云开发的云函数功能，部署自己的公网云服务。像用Express开发Web服务一样简单，并且提供了本地debug工具，该工具同样可以用于部署在服务器上。

## Usage

-  你的目录结构(可利用腾讯云提供的脚手架初始化云函数)
```
 rootDir
  - FunctionA
    - index.js(ts)
    - package.json

  - FunctionB
    - index.js(ts)
    - package.json
...
```
- 配置文件package.json
```json
{
  "name": "函数名，请保持环境内唯一性",
  "version": "1.0.0",
  "description": "",
  "main": "入口文件地址，默认为index.js",
  "scripts": {
    "dev": "可以写本地启动的脚本"
  },
  "author": "Tink Cai",
  "license": "ISC",
  "dependencies": {

  },
  "webservice": {
    "path": "该云函数的http访问路径，若为根路径则写/"
  },
  "envVariables": [
    "环境变量名，这里只写变量的Keys，对应的value在CI里设置，请等待1.x.x版本"
  ],
  "skipDeployment": false,
  "isCompressed": true,
  "layers": [
    {
      "name": "层名字",
      "version": 1
    }
  ]
}

```

- 如何使用，引用时注意路径
```javascript
import {Router} from "../../src";
import path from "path";
import apiRouter from './routers/api.router';
import bodyParser from '../../src/middlewares/body.parser';
import cookieParser from "../../src/middlewares/cookie.parser";

const createApp = (request, context) => {
  const app = new Router(request, {
    templateFolder: path.join(__dirname, 'templates'),
    defaultTemplateData: { translation: {}, namespace: '' }
  });
  // 将cookie和body转化成对象放在req对象里
  app.use(bodyParser);
  app.use(cookieParser);

  // middleware
  app.use(async (req, res, next) => {
    // todo something such as logging
    console.log(req);
    await next();
  });

  // 一个普通的路由
  app.get('/', async (req, res, next) => {
    res.text('Welcome!');
  });

  // 若将路由写在多个文件内，用extends方法，路由会按顺序遍历执行
  app.extends(apiRouter);

  // 请将该方法写在最底下
  app.get(async (req, res, next) => {
    res.statusCode = 404;
    res.text('not-found');
  });

  return app;
};

const main = async (request, context) => {
  const app = createApp(request, context);
  return app.serve();
};

// 保持以下两个方法的输出，main方法用于云函数的入口，createApp方法用于本地启动入口
export {main, createApp};

```

-  如何上传（推荐集成CI/CD功能，在1.x.x版本会后续上线）
其中index.js为默认的云函数入口文件，其中的main方法为默认的入口方法。
若您使用js编写云函数，可以直接上传对应的文件夹作为云函数;若您使用typescript编写，则需要将编译后的文件夹打包上传。


### Local simulator
因为是云原生的产品，所以本地调试一直没有很好的支持工具。若您有多个云函数组成一个完整的Web服务，本地很难将他们全部集成在一个服务里。这里介绍一下本地启动的模拟器如何配置和运行。

- 配置
server.config.json
```json
{
  "appPath": "存放云函数的根文件夹，注意不是某一个云函数的文件夹位置。例如./",
  "functionEnvVariables": {
    "STAGE": "云函数需要用到环境变量时，将环境变量配置到此处。以Key/Value形式保存"
  },
  "context": {
    "appId": "wx7ce310ee1e4efd39",
    "uin": "mockuintinkcai831",
    "envId": "local"
  },
  "port": 8081,
  "protocol": "http"
}
```
支持本地启动https服务，用来在云服务器上做生产环境部署。将port改为443，protocol改为https。并且在deploy时，传入证书文件。

- 如何deploy，请拷贝项目demo下的server.ts文件作为启动文件即可。若您需要用https服务启动，则修改deploy时的参数
```typescript
//  以上同
getApps().then((apps) => {
  console.log(apps);
  simulator.deploy(async (request: C4CApiRequest, context: Record<string, any>) => {
    for (let app of apps) {
      if (request.path.startsWith(app.path)) {
        const newRequest = Object.assign(request);
        let newPath = request.path.replace(app.path, '');
        if (!newPath.startsWith('/')) {
          newPath = '/' + newPath;
        }
        newRequest.path = newPath;
        const newApp = app.entrance.createApp(
          newRequest,
          context
        );
        return newApp.serve();
      }
    }
  }, {
    key: fs.readFileSync(keyPath),
    cert: fs.readFileSync(certPath)
  });
});


```
