{"id":15192501,"url":"https://github.com/node-wechat/koa-api-client","last_synced_at":"2026-03-05T11:04:53.561Z","repository":{"id":143882684,"uuid":"83453124","full_name":"node-wechat/koa-api-client","owner":"node-wechat","description":"rest api client for koa","archived":false,"fork":false,"pushed_at":"2017-11-10T09:12:06.000Z","size":37,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-23T11:33:53.689Z","etag":null,"topics":["koa","koa2","mock","rest-api"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/node-wechat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-28T16:13:32.000Z","updated_at":"2017-03-01T11:40:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"6a9b6d52-5fa2-4f2b-b62e-3a9aff03ad18","html_url":"https://github.com/node-wechat/koa-api-client","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-wechat%2Fkoa-api-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-wechat%2Fkoa-api-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-wechat%2Fkoa-api-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-wechat%2Fkoa-api-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/node-wechat","download_url":"https://codeload.github.com/node-wechat/koa-api-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241255995,"owners_count":19934965,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["koa","koa2","mock","rest-api"],"created_at":"2024-09-27T21:41:12.489Z","updated_at":"2025-02-28T22:25:30.186Z","avatar_url":"https://github.com/node-wechat.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# koa-api-client\n支持离线的请求客户端，允许前端按照对应的接口规则创建模拟数据，然后离线进行前端流程测试\n\n## 安装\n```\nnpm install koa-api-client\n```\n\n* [1.x](https://github.com/node-wechat/koa-api-client/blob/v1.x/README.md) for koa 1.x\n```\nnpm install koa-api-client@~1\n```\n\n## 支持的功能:\n\n### 基础功能\n1. 支持返回数据格式为`json`的请求\n\n### 扩展功能\n1. 读取模拟数据;\n2. 记录请求的数据;\n\n## 用法\n\n### 1.常规请求\n```js\nlet baseUri = {\n    scheme: 'http',\n    domain: '127.0.0.1',\n    port: port,\n    prefix: '/api/v1'\n};\nlet api = new ApiClient(baseUri, {\n    timeout: 15000, //网络请求超时时间\n    mock: process.env.NODE_ENV === 'production', //访问模拟数据\n    record: false, //记录请求返回的数据\n    beforeEnd: res =\u003e res //全局数据过滤器，对返回的数据做统一的处理\n})\n\napi.get('/banks', {type: 1}).then(...)\n//this will request http://127.0.0.1/api/api/banks?type=1\n//params will be cast to query params when request method is GET\n```\n\n### 2.多数据端请求\n```js\nlet userApi = new ApiClient({domain: 'user.apiserver.com', prefix: '/v1'});\nlet activityApi = new ApiClient('http://activity.apiserver.com/v2');\n\nuserApi.post('/users/add', {name: 'userName', age: 18}.then(...)\nactivityApi.get('/activities', {startTime: '20170228'}.then(...)\n```\n\n### 3.读取模拟数据\n具体用法可以参见/test/index.js中的后两个测试用例\n```js\nlet recordFolder = path.join(__dirname, '/mock');\nlet apiClient = new ApiClient(baseUri, {\n    mock: {\n        sleep: 1000, //模拟请求消耗时长\n        suffix: '.json', //数据文件后缀\n        dirLevel: MOCK_DIR_LEVEL, //相对请求路径的深度,默认为0\n        base: recordFolder //模拟数据的跟目录，配合dirLevel使用\n    }\n});\n\napiClient.get('/banks', {\n    type: 1\n}).then(res =\u003e {\n    //数据内容包含某个节点\n    expect(res.data['ABC']).to.have.property('name');\n\n    done();\n}).catch(err =\u003e {\n    done(err);\n})\n```\n\n### 4.记录数据请求\n具体用法可以参见/test/index.js中的后两个测试用例\n```js\nlet recordFolder = path.join(__dirname, '/mock');\nlet apiClient = new ApiClient(baseUri, {\n    record: {\n        suffix: '.json',\n        dirLevel: MOCK_DIR_LEVEL,\n        base: recordFolder\n    }\n});\n\nlet recordFilePath = recordFolder + path.sep + 'api/v1/banks'.split('/').slice(MOCK_DIR_LEVEL).join(path.sep) + '.json';\nif (fs.existsSync(recordFilePath)) {\n    fs.unlinkSync(recordFilePath);\n}\n\napiClient.get('/banks', {\n    type: 1\n}).then(res =\u003e {\n    fs.readFile(recordFilePath, 'utf8', function (err, data) {\n        assert.deepEqual(JSON.parse(data)\n            , res, 'file content is some with request content');\n\n        done(err);\n    });\n}).catch(err =\u003e {\n    done(err);\n})\n```\n\n### 5.开启数据日志记录\n#### persistent mode log for production environment\n```js\nvar log4js = require('log4js'); //log4js@~1\nlog4js.configure({\n      appenders: [\n            { type: 'console' },\n            { type: 'file', filename: 'logs/api.log', category: 'koa-api-client' }\n      ]\n});\n//set global logger for ApiClient\nApiClient.injectLogger(log4js.getLogger('koa-api-client'));\n\nlet api = new ApiClient('http://api.server.com/v1', {});\n```\nYou can use any logger engine instance, it will detect the log node or log's info node(require type:function).\n\n#### log for debug\nwe use the `debug` lib to console logs; set DEBUG=koa-api-client to console logs, more [docs](https://github.com/visionmedia/debug#windows-note).\n\n### 6.custom dataParser\nsupport each ApiClient and each request config\n```js\nvar xmlParser = require('xml2json');\nvar apiClient = new ApiClient(baseUri, Object.assign({\n    dataParser: (err, data) =\u003e err ? {\n        success: false,\n        msg: err.message\n    } : JSON.parse(xmlParser.toJson(data)).root\n}, defaultOpt));\n\n// server side will return '\u003croot\u003e\u003cdata\u003e\u003cABC\u003ebank\u003c/ABC\u003e\u003c/data\u003e\u003ccode\u003e0\u003c/code\u003e\u003c/root\u003e'\napiClient.get('/xml').then(res =\u003e {});;\n//content is {data: {ABC: bank}, code: 0}\n```\n\n### 7.set data handler list by config.beforeEnd\n\u003e not support in each request's config\n\n```js\nvar apiClient = new ApiClient(baseUri, Object.assign({\n    beforeEnd: [\n        //if has valid data node, set success is true\n        data =\u003e {\n            data['success'] = !!data.data\n            return data;\n        },\n        //convert json node key to upper mode\n        data =\u003e {\n            Object.keys(data)\n                .forEach(key =\u003e {\n                    data[key.toUpperCase()] = data[key];\n                    delete data[key];\n                })\n            return data;\n        },\n        //log return data\n        data =\u003e {\n            console.log(JSON.stringify(data));\n            return data;\n        }\n    ]\n}, defaultOpt));\n\napiClient.get('/notfound').then(res =\u003e {});\n```\n\n### 8.request middleware support\n1.server side use snake mode json data\n```js\nrouter.get('/codeType/snake', function (cxt){\n    var snakeType = cxt.request.query['snake_type'];\n\n    if(snakeType){\n        cxt.body = {\n            success: true,\n            data: {\n                user_id: 'fadslkjfldaksjlf',\n                user_name: 'userName',\n                user_age: 27\n            }\n        };\n    }\n})\n```\nclient side also use snake mode, but now need to use camel mode,\nso can set requestMiddleware to convert request params and response data\n```js\nvar apiClient = new ApiClient(baseUri, Object.assign({\n    requestMiddleware: [\n        function (cxt, next) {\n            var request = cxt;\n\n            if (request.params) {\n                request.params = humps.decamelizeKeys(request.params);\n            }\n\n            return next()\n                .then(() =\u003e {\n                    if (request.data) {\n                        request.data = humps.camelizeKeys(request.data)\n                    }\n                });\n        }\n    ]\n}, defaultOpt));\n\napiClient.get('/codeType/snake', {snakeType: 1}).then(res =\u003e {});\n```\nnow, client use camel mode data without server side changes\n\n## TODO\n1. 需要考虑如何支持参数在链接上形式下，数据如何模拟读取和保存\n1. 通过mock数据约定格式，校验后台生产环境返回的数据，避免格式变更导致的前端报错\n1. ~~增加自定义的数据过滤函数池，统一对后台返回数据做处理。例如，蛇底转换成驼峰~~(config.beforeEnd/config.requestMiddleware)\n\n### update list\n\n##### 1.2.0\n1. add advanced options requestMiddleware, you can set make some changes before and after request\n1. export injectLogger from ApiClient module directly, not from instance config\n1. add dataParser to custom convert data\n1. remove log4js module, accept log implement from option params. \n\n##### 2.0.5\nuse json5 to parse mock file, instead of json default\n\n##### 2.0.4\n优化ApiClient的使用场景，允许无baseUri的实例化(`utils.parseUriConfigToString`增加`strictMode`参数)\n\n##### 2.0.3\n修复url上存在参数后，自动补充参数错误的BUG\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnode-wechat%2Fkoa-api-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnode-wechat%2Fkoa-api-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnode-wechat%2Fkoa-api-client/lists"}