from typing import Optional, Any
from mypy_extensions import TypedDict
from flask.json import dumps
from flask import current_app, Response
RESP_MSGS = {
200: 'ok',
400: 'failed',
401: '未登录',
403: '未授权',
404: '不正确的链接地址',
422: '请求数据校验失败',
500: '服务器内部错误',
}
[文档]class RespType(TypedDict):
code: str
message: str
detail: Any
[文档]def gen_response(code: int, message: str = None, detail: Optional[str] = None,
data=None) -> RespType:
"""Func for generate response body.
Args:
code (string, int): Extension to interact with web pages. Default is \
http response ``status_code`` like 200、404.
message (string): For popup windows.
data (object): Real response payload.
detail (object): For debug, detail server error msg.
Returns:
dict: A dict contains all args.
2021-07-08 Updated:
Default type of `code` in response is force conversion to `str`, now
support set `HOBBIT_USE_CODE_ORIGIN_TYPE = True` to return origin type.
2021-07-13 Updated:
Support set `HOBBIT_RESPONSE_MESSAGE_MAPS` to use self-defined
response message. `HOBBIT_RESPONSE_MESSAGE_MAPS` must be dict.
"""
use_origin_type = current_app.config.get(
'HOBBIT_USE_CODE_ORIGIN_TYPE', False)
resp_msgs = current_app.config.get('HOBBIT_RESPONSE_MESSAGE_MAPS', {})
assert isinstance(resp_msgs, dict), \
'HOBBIT_RESPONSE_MESSAGE_MAPS must be dict type.'
if not message:
message = resp_msgs.get(code)
if message is None:
message = RESP_MSGS.get(code, 'unknown')
if current_app.config.get("HOBBIT_RESPONSE_DETAIL", True) is False \
and code == 500:
detail = None
return {
'code': str(code) if use_origin_type is False else code,
'message': message, # type: ignore
'data': data,
'detail': detail,
}
[文档]class Result(Response):
"""Base json response.
"""
_hobbit_status = 200 # type: ignore
def __init__(self, response=None, status=None, headers=None,
mimetype='application/json', content_type=None,
direct_passthrough=False):
assert sorted(response.keys()) == [
'code', 'data', 'detail', 'message'], \
'Error response, must include keys: code, data, detail, message'
super().__init__(
response=dumps(response, indent=0, separators=(',', ':')) + '\n',
status=status if status is not None else self._hobbit_status,
headers=headers, mimetype=mimetype,
content_type=content_type, direct_passthrough=direct_passthrough)
[文档]class SuccessResult(Result):
"""Success response. Default status is 200, you can cover it by status arg.
"""
_hobbit_status = 200
def __init__(self, message: str = '', code: Optional[int] = None,
detail: Any = None, status: Optional[int] = None, data=None):
super().__init__(
gen_response(code if code is not None else self._hobbit_status,
message, detail, data),
status or self._hobbit_status)
[文档]class FailedResult(Result):
"""Failed response. status always 400.
"""
_hobbit_status = 400
def __init__(self, message: str = '', code: Optional[int] = None,
detail: Any = None):
super().__init__(
gen_response(
code if code is not None else self._hobbit_status,
message, detail),
self._hobbit_status)
[文档]class UnauthorizedResult(FailedResult):
_hobbit_status = 401
[文档]class ForbiddenResult(FailedResult):
_hobbit_status = 403
[文档]class ValidationErrorResult(FailedResult):
_hobbit_status = 422
[文档]class ServerErrorResult(FailedResult):
_hobbit_status = 500