weroll的API统一使用 [POST] http://域名/api 作为入口,请求和响应数据使用json格式
一个典型的weroll的API是这样的:
- General -
Request URL: http://localhost:3000/api
Request Method: POST
- Request Header -
Content-Type: application/json; charset=UTF-8
- Request Payload / Post Data -
{ "method":"user.hello","data":{"name":"Jay","gender":"1"} }
// method 表示接口名称, data 表示请求参数
- Response Header -
Content-Type: application/json
- Response Data -
{"code":1,"data":{"a":1, "b":2},"msg":"OK"}
// code 表示错误码, 1表示正确, data 表示响应的结果数据, msg 表示消息, 当 code > 1 时则是错误的具体描述
在 server/service目录中,新建一个脚本文件,比如UserService.js。Service文件必须在server/service目录或其子目录中,weroll在启动时会自动遍历里面的所有js文件,注册API。以下是一个典型的Service代码
//./server/service/UserService.js
//配置这组API的前缀名和各个接口的参数定义
exports.config = {
name: "user", //定义这组api的前缀名为user
enabled: true,
security: {
//按照以下注释的写法,API调试工具可以自动识别这些说明并在工具中显示出来
//@hello 打个招呼 @name 名字 @gender 性别,1-男,2-女
"hello":{ needLogin:false, checkParams:{ name:"string" }, optionalParams:{ gender:"int" } },
//@bye 说再见 @name 名字
"bye":{ needLogin:false, optionalParams:{ name:"string" } },
//@ip 获取当前登录用户的IP地址
"ip":{ needLogin:true }
}
};
exports.hello = (params) => {
let { name, gender } = params.name;
return { msg:`欢迎, 你的名字是${name}, 性别是${gender == 1 ? "男" : "女"}` };
}
//异步接口
exports.bye = async (params) => {
let name = params.name || "陌生人";
let asyncJob = (name) => {
return new Promise(resolve => {
setTimeout(() => {
resolve({ msg:`再见, ${name}` });
}, 200);
});
}
let result = await asyncJob();
return result;
}
//使用user, req, res参数
exports.ip = (params, user, req, res) => {
let result = { msg:`用户: [${user.id}], IP: ${req._clientIP}` };
// res.sayOK(result); // 等同于直接return
return result;
}
通过以上代码,我们定义了一组前缀为user的接口,并创建了2个具体的方法 user.hello 和user.bye
现在启动程序,在浏览器中打开以下页面使用API调试工具进行测试
http://localhost:3000/__test
这是weroll自带的API调试工具,你可以使用这个工具调试进行API接口调试,它会自动解析出所有定义在service目录下的API接口,并识别其中的注释,将其变成API接口描述和参数的说明。
当然你也可以使用PostMan一类的工具进行调试。
在API方法参数中的 req 对象,如果你使用的是WebApp类建立http服务,req对象则是Express框架中的Request对象,请参考Express的官方文档中的Request说明。
如果你使用的是APIServer类建立http服务,req对象则是原生http库中的request对象,请参考Node.js官方文档。
weroll对req对象添加了一些新的属性和方法,以便我们更有效率的开发
Property | Description |
req._clientIP | 客户端的IP地址 |
req._identifyID | 客户端的uuid,由weroll在客户端第一次请求时生成,可用于统计在线用户数等业务场景,请参考源代码 |
Method | Description |
req.callAPI() | 调用其他的API方法,如 req.callAPI("user.hello", { name:"Jay" }, session, callBack)。这样我们就可以在任何一个路由或者任何一个API代码段中,调用任何一个API,使API得到重复利用。 |
在API方法参数中的 res 对象,如果你使用的是WebApp类建立http服务,res对象则是Express框架中的Response对象,请参考Express的官方文档中的Response说明。
如果你使用的是APIServer类建立http服务,res对象则是原生http库中的response对象,请参考Node.js官方文档。
同样,weroll也对res对象添加了一些新的方法
Method | Description |
res.sayOK() | 响应正确结果给客户端,使用json对象作为参数,如果不写参数,则客户端会得到:
|
res.sayError() | 响应错误结果给客户端,可使用Error对象,String对象或者[ code, msg ]作为参数
|
res.done() | 响应结果给客户端 如果err存在,则执行res.sayError(err),否则将执行res.sayOK(result) |
res.exec() | 执行一个数组任务队列,然后将结果响应给客户端。使用数组对象作为参数,请参考async库中的waterfall方法
res.exec相当于执行了async.waterfall方法,如果队列中的任意一个callback传递了存在的err对象,则队列中断,执行res.sayError(err) 将错误响应给客户端,否则将依次执行队列中的代码段,最后执行res.sayOK |
通过 exports.config.security 配置,我们可以给每一个API设定可选参数(optionalParams)和必须参数(checkParams),可以只有可选参数或必须参数,也可以都不设定。
weroll自带了以下请求参数类型检查:
Type | Description |
string | 字符串 - 如"Jay Liang",如果是必须参数,则不能为空字符串 |
number | 数字 - 如2322,-80,100.31或者"999",如果是String,则会转换成Number |
int | 整数 - 如100或者"100",如果是String,则会转换成Number,如果是浮点数,则会变成整数 |
boolean | 布尔值 - 如1或0,true或false |
object | 对象 - 如{ "name":"Jay", gender:1 } 或者 [ "Jay", 1 ] |
array | 数组对象 - 如 [ "Jay", 1 ] |
geo | 经纬度坐标 - 如 "121.47213,31.34533" 或者 [ 121.47213,31.34533 ],最终将转为[ 经度,纬度 ] |
电子邮箱 - 如 "123@456.com" | |
cellphone | 中国手机号码 - 如 "18600000000" |
请参考源代码 weroll/utils/ParamsChecker
开发者还可以自定义参数类型,示例代码如下:
/* somewhere */
//custom check function
//only accept format: "上海|上海市|福州路1000号"
var locationCheck = function(val) {
if (typeof val != "string") return { value:null, err:new Error("invalid format") };
val = val.split("|");
if (val.length < 3) return { value:null, err:new Error("invalid format") };
var loc = { province:val[0], city:val[1], street:val[2] };
return { value:loc };
}
//register
var ParamsChecker = require("weroll/utils/ParamsChecker");
ParamsChecker.register("location", locationCheck);