之前项目中用到 openresty 作为 Web Api 的开发平台, 用 openresty 很适合开发以 http 接口形式 提供的服务. openresty 可以使用 lua 进行逻辑控制,加上完备的组件driver(redis, mysql, rabbitmq 等), 只需要写业务代码将各种数据读取,加工,输出,就是充当胶水的角色.
最重要的一点是, openresty + lua 已经很好的处理并行(开多个 nginx worker即可)和并发(lua coroutine), lua vm 已经默默的处理了阻塞的IO操作,开发人员可以用写同步代码的方式实现异步.
既然是 Web Api,自然少不了对参数的校验, validator库实现对 lua table 的校验.
安装
把 validator.lua 文件放入 openresty 安装目录的 lualib/resty/
下即可.
Demo
location /validator_demo {
content_by_lua_block {
local v = require("resty.validator")
local cjson = require("cjson")
local user = {
id = {
type = v.NUMBER,
required = true,
},
name = {
type = v.STRING,
required = true,
},
addr = {
type = v.OBJECT,
required = true,
struct = {
city = {
type = v.STRING,
required = true,
minlength = 2,
},
postcode = {
type = v.STRING,
required = true,
minlength = 6,
maxlength = 6,
}
}
}
}
ngx.req.read_body()
local body = ngx.req.get_body_data()
local json = cjson.decode(body)
local ok, user, err = v.bind(user, json)
if not ok then
ngx.say(err)
else
ngx.say(cjson.encode(user))
end
}
}
$ curl -d '{}' 'http://localhost/validator_demo'
'addr' is required
$ curl -d '{ "addr":{ "city": "guangzhou" } }' 'http://localhost/validator_demo'
'addr.postcode' is required
$ curl -d '{ "addr":{ "city": "guangzhou", "postcode": "510000" } }' 'http://localhost/validator_demo'
'name' is required
$ curl -d '{ "name": "xsyr", "addr":{ "city": "guangzhou", "postcode": "510000" } }' 'http://localhost/validator_demo'
'id' is required
$ curl -d '{ "id" : 100, "name": "xsyr", "addr":{ "city": "guangzhou", "postcode": "510000" } }' 'http://localhost/validator_demo'
{"addr":{"city":"guangzhou","postcode":"510000"},"name":"xsyr","id":100}
参数类型定义
1. NUMBER - 数值类型
绑定语法:
<field> = {
-- 数值类型(必填)
type = validator.NUMBER,
-- 默认值(可选,默认为 nil)
default = 0,
-- 是否必填项(可选,默认为 false)
required = true,
-- checker 执行前的处理函数,函数的返回值用作后续的处理(可选,默认无)
-- 执行顺序:pre, checker, post
pre = function(val) return dosth(val) end,
-- 对填写的值进行校验,返回 res, err (可选,默认无)
-- res: 校验的结果(true/false)
-- err: 如果校验不通过(res = false)的错误提示信息,如果不填
-- 则使用 err_msg。
checker = function(val, field) return docheck(val) end,
-- checker 执行后的处理函数,函数的返回值作为最终 field 的值(可选,默认无)
post = function(val) return dosth(val) end,
}
2. STRING - 字符串类型
绑定语法:
<field> = {
-- 数值类型(必填)
type = validator.STRING,
-- 默认值(可选,默认为 nil)
default = "unknown",
-- 是否必填项(可选,默认为 false)
required = true,
-- checker 执行前的处理函数,函数的返回值用作后续的处理(可选,默认无)
-- 执行顺序:pre, minlength, maxlength, checker, post
pre = function(val) return dosth(val) end,
-- 最小长度(可选,默认 nil 无限制)
minlength = 1,
-- 最大长度(可选,默认 nil 无限制)
maxlength = 5,
-- 对填写的值进行校验,返回 res, err (可选,默认无)
-- res: 校验的结果(true/false)
-- err: 如果校验不通过(res = false)的错误提示信息,如果不填
-- 则使用 err_msg。
checker = function(val, field) return docheck(val) end,
-- checker 执行后的处理函数,函数的返回值作为最终 field 的值(可选,默认无)
post = function(val) return dosth(val) end,
}
3. OBJECT - 对象类型(对象成员的类型可以是任意类型(NUMBER, STRING, …))
绑定语法:
<field> = {
-- 数值类型(必填)
type = validator.OBJECT,
-- 默认值(可选,默认为 nil)
default = { a = 1, b = 2 },
-- 是否必填项(可选,默认为 false)
required = true,
-- 对象的结构(必填)
struct = {
-- 对象的成员,成员的类型可以为 NUMBER, STRING, OBJECT
<member> = {
type = STRING, -- 成员的类型,详见 STRING 类型的定义
required = true,
...
},
...
}
-- checker 执行前的处理函数,函数的返回值用作后续的处理(可选,默认无)
-- 执行顺序:pre, checker, post
pre = function(val) return dosth(val) end,
-- 对填写的值进行校验,返回 res, err (可选,默认无)
-- res: 校验的结果(true/false)
-- err: 如果校验不通过(res = false)的错误提示信息,如果不填
-- 则使用 err_msg。
checker = function(val, field) return docheck(val) end,
-- checker 执行后的处理函数,函数的返回值作为最终 field 的值(可选,默认无)
post = function(val) return dosth(val) end,
}
4. ARRAY - 数组类型(数组元素的类型可以是任意类型(NUMBER, STRING, …))
绑定语法:
<field> = {
-- 数值类型(必填)
type = validator.ARRAY,
-- 默认值(可选,默认为 nil)
default = {},
-- 是否必填项(可选,默认为 false)
required = true,
-- 数组元素的结构(可以是任意类型)
element = {
type = NUMBER, -- 可以是任意类型,类型的绑定语法详见各类型的说明
...
},
-- checker 执行前的处理函数,函数的返回值用作后续的处理(可选,默认无)
-- 执行顺序:pre, minlength, maxlength, checker, post
pre = function(val) return dosth(val) end,
-- 最小长度(可选,默认 nil 无限制)
minlength = 1,
-- 最大长度(可选,默认 nil 无限制)
maxlength = 5,
-- 对填写的值进行校验,返回 res, err (可选,默认无)
-- res: 校验的结果(true/false)
-- err: 如果校验不通过(res = false)的错误提示信息,如果不填
-- 则使用 err_msg。
checker = function(val, field) return docheck(val) end,
-- checker 执行后的处理函数,函数的返回值作为最终 field 的值(可选,默认无)
post = function(val) return dosth(val) end,
}
5. STRINGIFY_OBJECT - 字符串化的对象类型(对象成员的类型可以是任意类型(NUMBER, STRING, …))
如: module = "{\"type\":\"audio\",\"id\":1}"
绑定语法:
<field> = {
-- 数值类型(必填)
type = validator.STRINGIFY_OBJECT,
-- NOTE: 其他定义与 OBJECT 相同
}
6. STRINGIFY_ARRAY - 数组类型(数组元素的类型可以是任意类型(NUMBER, STRING, …))
如: lists = "[{\"type\":\"audio\",\"id\":1},{\"type\":\"album\",\"id\":2}]"
绑定语法:
<field> = {
-- 数值类型(必填)
type = validator.STRINGIFY_ARRAY,
-- NOTE: 其他定义与 ARRAY 相同
}