Mock Server
基于Flask实现的一个简易Mock平台,使用标准json结构体编写Mock Api https://github.com/yinquanwang/MockServer
Key Features
遵循Http协议,支持GET 、POST 、PUT 、DELETE 常用http请求方式
mock结构体为标准json结构,支持参数内容规则制定以及对象返回信息
内置常用校验器,equals、contains、between、length、type, 可灵活自己扩展
支持自定义报文Valid与Invalid,返回报文可以是任意类型
数据类型丰富,支持string、int、float、list、dict
得益于Flask强大的路由系统,设计核心就是将所有请求的path归一化到一个视图函数处理: @app.route('/', methods=['GET', 'PUT', 'DELETE', 'POST'])
def dispatch_request(path):
"""
mock view logic
:param path: request url for mock server
:return: response msg that use default or custom defined
"""
m = models.Api.query.filter_by(url=request.path, method=request.method).first_or_404()
body = json.loads(m.body)
return domain_server(**body)
@app.errorhandler(404)
def url_not_found(error):
return json.dumps({
"status": 404,
"msg": "the request url not found,please check"
})
如果mock脚本不自定义返回报文,由系统默认提供,默认标准json结构体 VALID = {
"success": True,
"code": "0000",
"msg": "success"
}
INVALID = {
'code': '0020',
'msg': 'request data invalid',
'success': False
}
MISS = {
'code': '0021',
'msg': 'request data missed',
'success': False
}
TYPE_NOT_MATCH = {
"success": False,
"code": "0001",
}
EQUALS = {
"success": False,
"code": "0005",
}
NOT_BETWEEN = {
"success": False,
"code": "0007",
}
STR_NOT_CONTAINS = {
"success": False,
"code": "0004",
}
STR_TOO_LONG = {
"success": False,
"code": "0006",
}
由此我们必须实现一个校验器,对各个字段进行一些基本校验 class Validator:
"""
Validator for mock check
"""
@classmethod
def valid(cls, response=None):
return get_response(response, VALID)
@classmethod
def type_not_match(cls, type, data, response=None):
msg = '{data} must be {type} type'.format(data=data, type=type)
TYPE_NOT_MATCH['msg'] = msg
if type == 'int':
if not isinstance(data, int):
return get_response(response, TYPE_NOT_MATCH)
elif type == 'float':
if not isinstance(data, float):
return get_response(response, TYPE_NOT_MATCH)
elif type == 'string':
if not isinstance(data, str):
return get_response(response, TYPE_NOT_MATCH)
elif type == 'bool':
if not isinstance(data, bool):
return get_response(response, TYPE_NOT_MATCH)
elif type == 'list':
if not isinstance(data, list):
return get_response(response, TYPE_NOT_MATCH)
elif type == 'dict':
if not isinstance(data, dict):
return get_response(response, TYPE_NOT_MATCH)
else:
return False
@classmethod
def is_not_equals(cls, data, expect, response=None):
if data != expect:
msg = '{data} must be equals {expect}'.format(data=data, expect=expect)
EQUALS['msg'] = msg
return get_response(response, EQUALS)
else:
return False
@classmethod
def is_not_between(cls, data, between, response=None):
try:
min = between[0]
max = between[1]
except IndexError:
return {'msg': 'mock config error'}
if data > max or min < min:
msg = '{data} must be between in {between}'.format(data=data, between=between)
NOT_BETWEEN['msg'] = msg
return get_response(response, NOT_BETWEEN)
else:
return False
@classmethod
def is_not_contains(cls, data, expect, response=None):
if data not in expect:
msg = '{data} not in {expect}'.format(data=data, expect=expect)
STR_NOT_CONTAINS['msg'] = msg
return get_response(response, STR_NOT_CONTAINS)
else:
return False
@classmethod
def is_too_long(cls, data, length, response=None):
if len(data) > length:
msg = '{data} is too long, max length is {length}'.format(data=data, length=length)
STR_TOO_LONG['msg'] = msg
return get_response(response, STR_TOO_LONG)
else:
return False
接下来便是对请求数据与期望数据匹配,从而返回相应报文了 def domain_server(**kwargs):
"""
used for POST PUT DELETE
:param kwargs: standard json mock scripts
:return: response msg
"""
data = kwargs.get('data', {})
invalid = kwargs.get('invalid', {})
if request.json:
form = request.json
elif request.form:
form = request.form
elif request.args:
form = request.args
if data is {}: # do not have any parameters
return Validator.valid(response=kwargs.get('valid'))
else:
if len(form) != len(data): # data do not matched
return json.dumps(MISS, ensure_ascii=False)
for key in form.keys():
if key not in data.keys():
return json.dumps(INVALID, ensure_ascii=False)
for key, value in form.items(): # usually validators
expect = data.get(key)
type = expect.get('type')
msg = Validator.type_not_match(type, value, response=invalid.get('type'))
if msg:
return msg
contains = expect.get('contains')
if contains:
msg = Validator.is_not_contains(value, contains, response=invalid.get('contains'))
if msg:
return msg
equals = expect.get('equals')
if equals:
msg = Validator.is_not_equals(value, equals, response=invalid.get('equals'))
if msg:
return msg
long = expect.get('long')
if long:
msg = Validator.is_too_long(value, long, response=invalid.get('length'))
if msg:
return msg
between = expect.get('between')
if between:
msg = Validator.is_not_between(value, between, response=invalid.get('between'))
if msg:
return msg
return Validator.valid(response=kwargs.get('valid'))
指导说明
example for get request
json
{
"data": {
"password": {
"equals": "lcc",
"type": "string"
},
"username": {
"equals": "lcc",
"type": "string"
}
},
"invalid": {
"equals": {
"msg": "恭喜啊,查询到该账号了"
},
"type": "类型不匹配啊"
},
"method": "GET",
"name": "查询接口",
"url": "/get/",
"valid": {
"msg": "查询成功啦",
"success": true
}
}
例如上述json结构体,此get请求有两个参数username,password, type=string,equals=lcc ,规定了valid报文和invalid中的equals报文
example for post
支持json和form,系统会自动进行分辨
json
{
"data": {
"email": {
"equals": {
"lcc": "lcc@qq.com",
"yqw": "yqw@qq.com"
},
"type": "dict"
},
"password": {
"type": "string"
},
"username": {
"equals": "lcc",
"length": 10,
"type": "string"
}
},
"invalid": {
"equals": {
"msg": "哥们,类型不匹配啊"
},
"type": "类型不匹配啊"
},
"method": "POST",
"name": "注册接口",
"url": "/register/",
"valid": {
"msg": "注册成功啦"
}
}
example for put
json
{
"data": {
"identity": {
"equals": "1",
"type": "string"
}
},
"invalid": {
"equals": {
"msg": "啊哦 该账号没有记录哦"
},
"type": "类型不匹配啊"
},
"method": "put",
"name": "更新接口",
"url": "/put/",
"valid": {
"msg": "查询成功啦",
"success": true
}
}
example for delete
json
{
"data": {
"account": {
"equals": "lcc123456",
"length": 10,
"type": "string"
}
},
"invalid": {
"equals": {
"msg": "啊哦 该账号没有记录哦"
},
"type": "类型不匹配啊"
},
"method": "delete",
"name": "删除接口",
"url": "/del/1/",
"valid": {
"msg": "删除成功啦",
"success": true
}
}
## 由于第一次接触Flask,mock的理解自己可能也有偏差,所以还请各位大神不要见怪
本地开发环境部署
git clone 或者 checkout至本地目录
修改:MockServer/config.py 数据库相关配置
python
USERNAME = 'root'
PASSWORD = 'lcc123456'
HOST = '127.0.0.1'
DB = 'MockServer'
安装相应依赖库
bash
pip install -r requirements.txt
创建MockServer数据库, 默认DB是MockServer
生成数据库迁移脚本,应用表结构
bash
python manage.py db init
python manage.py db migrate
python manage.py db upgrade
Start Server
bash
python run.py