Flask后端实践 连载三 接口标准化及全球化

Flask 接口标准化及全球化

tips:

  • 本文主要解决项目中历史遗留问题,将产品正规化,统一接口返回,实现全球化。
  • 本文基于python3编写
  • 代码仓库

项目场景

某日,本人终于受不了前人挖坑,大怒!!!V1版本项目restful接口返回一团糟,没有固定的格式,前端大佬也是抱怨多次。在本人的积极怂恿下,项目经理决定重写项目,解决诸多历史遗留问题(多得我想哭,自找的)。

接口统一返回形式

  1. 网上收罗一大圈,一般接口响应消息包含错误编码、信息以及数据
  2. 类似定义如下:
    {
    	"code":0,
    	"msg":"成功",
    	"data":null
    }
    
  • code:表示响应状态码
  • msg:表示响应消息
  • data:表示响应数据

响应状态码及响应消息

  1. 成功类,包含0以及200开头的数字
编码含义
0成功
20001登录成功
  1. 错误类,400开头的数字
编码含义
-1失败
40000自定义错误("{model} not have {key} ")
40001账户或密码错误
40002参数无效
40003未找到相关资源
  1. 服务器错误类,500开头的数值
编码含义
50001服务器错误,请联系管理员
50002计算出错

Flask接口返回设计

  1. 编写响应码类和响应消息类(code.py

    class ResponseCode(object):
        SUCCESS = 0  # 成功
        FAIL = -1  # 失败
        NO_RESOURCE_FOUND = 40001  # 未找到资源
        INVALID_PARAMETER = 40002  # 参数无效
        ACCOUNT_OR_PASS_WORD_ERR = 40003  # 账户或密码错误
        
    class ResponseMessage(object):
        SUCCESS = "成功"
        FAIL =  "失败"
        NO_RESOURCE_FOUND =  "未找到资源"
        INVALID_PARAMETER =  "参数无效"
        ACCOUNT_OR_PASS_WORD_ERR =  "账户或密码错误"
    
  2. Flask 接口返回实例(app.py)

    from flask import Flask,jsonify
    from code import ResponseCode,ResponseMessage
    
    app =Flask(__name__)
    
    @app.route("/",methods=["GET"])
    def test():
    	test_dict = dict(name="zhang",age=18)
    	data=dict(code=ResponseCode.SUCCESS,
    			  msg=ResponseMessage.SUCCESS,
    			  data=test_dict)
    	return jsonify(data)
    if __name__=="__main__":
    	app.run()
    

    运行app,访问 http://127.0.0.1:5000/ 返回如下:
    {"code":0,"data":{"age":18,"name":"zhang"},"msg":"成功"}

  3. 进一步封装响应文本(response.py),减少重复代码的编写量及保持代码清洁

    class ResMsg(object):
        """
        封装响应文本
        """
    
        def __init__(self, data=None, code=ResponseCode.SUCCESS, 
        			 msg=ResponseMessage.SUCCESS):
            self._data = data
            self._msg = msg
            self._code = code
    
        def update(self, code=None, data=None, msg=None):
            """
            更新默认响应文本
            :param code:响应状态码
            :param data: 响应数据
            :param msg: 响应消息
            :return:
            """
            if code is not None:
                self._code = code
            if data is not None:
                self._data = data
            if msg is not None:
                self._msg = msg
    
        def add_field(self, name=None, value=None):
            """
            在响应文本中加入新的字段,方便使用
            :param name: 变量名
            :param value: 变量值
            :return:
            """
            if name is not None and value is not None:
                self.__dict__[name] = value
    
        @property
        def data(self):
            """
            输出响应文本内容
            :return:
            """
            body = self.__dict__
            body["data"] = body.pop("_data")
            body["msg"] = body.pop("_msg")
            body["code"] = body.pop("_code")
            return body
    

    app中使用响应文本封装

    from flask import Flask, jsonify
    from code import ResponseCode, ResponseMessage
    from response import ResMsg
    
    app = Flask(__name__)
    
    
    @app.route("/", methods=["GET"])
    def test():
        res = ResMsg()
        test_dict = dict(name="zhang", age=18)
        res.update(data=test_dict)
        return jsonify(res.data)
    
    
    if __name__ == "__main__":
        app.run()
    
    

    运行app,访问 http://127.0.0.1:5000/ 返回如下:
    {"code":0,"data":{"age":18,"name":"zhang"},"msg":"成功"}

  4. 实现全球化配置

    实现思路是编写两份不一样的响应消息,前端通过选择语言,后端返回对应语言的消息。因此采用yaml编写响应消息,并加载到Flask应用中,通过语言选择返回不同的语言消息。在我的另外一篇文章《Flask后端实践 连载一 加载yaml配置文件》中介绍了Flask加载配置yaml文件。

  • 编写msg.yaml,中文响应消息(zh_CN),英文响应消息(en)
    zh_CN: &zh
      0: "成功"
      -1: "失败"
      40001: "资源不存在"
      40002: "参数无效"
      40003: "账户或密码错误"
    en:
      <<: *zh
      # 英文编码
      0: "success"
      -1: "fail"
      40001: "No resources found"
      40002: "Invalid argument"
      40003: "Incorrect account or password"
    
    
  • 修改(response.py),不使用ResponseMessage类
    from code import ResponseCode
    from flask import request, current_app
    
    
    class ResMsg(object):
        """
        封装响应文本
        """
    
        def __init__(self, data=None, code=ResponseCode.SUCCESS, rq=request):
            # 获取请求中语言选择,如果不存在,获取配置中的语言,如果配置中语言不存在,则默认为中文
            self.lang = rq.headers.get("lang", 
                                       current_app.config.get("LANG", "zh_CN") 
                                       )
            self._data = data
            self._msg = current_app.config[self.lang].get(code, None)
            self._code = code
    
        def update(self, code=None, data=None, msg=None):
            """
            更新默认响应文本
            :param code:响应编码
            :param data: 响应数据
            :param msg: 响应消息
            :return:
            """
            if code is not None:
                self._code = code
                # 获取配置中对应语言的响应消息,默认为None
                self._msg = current_app.config[self.lang].get(code, None)
            if data is not None:
                self._data = data
            if msg is not None:
                self._msg = msg
    
        def add_field(self, name=None, value=None):
            """
            在响应文本中加入新的字段,方便使用
            :param name: 变量名
            :param value: 变量值
            :return:
            """
            if name is not None and value is not None:
                self.__dict__[name] = value
    
        @property
        def data(self):
            """
            输出响应文本内容
            :return:
            """
            body = self.__dict__
            body["data"] = body.pop("_data")
            body["msg"] = body.pop("_msg")
            body["code"] = body.pop("_code")
            return body
    
    
  • 修改(app.py)内容,添加读取响应消息配置
    from flask import Flask, jsonify
    import yaml
    from code import ResponseCode
    from response import ResMsg
    
    app = Flask(__name__)
    
    with open("msg.yaml", encoding="utf-8") as f:
        msg_conf = yaml.safe_load(f)
    app.config.update(msg_conf)
    
    @app.route("/", methods=["GET"])
    def test():
        res = ResMsg()
        test_dict = dict(name="zhang", age=18)
        # 此处只需要填入响应状态码,即可获取到对应的响应消息
        res.update(code=ResponseCode.SUCCESS, data=test_dict)
        return jsonify(res.data)
    
    
    if __name__ == "__main__":
        app.run()
    
    

运行app,访问 http://127.0.0.1:5000/ ,利用postman设置不同的请求头,返回如下:
中文(headers中lang=zh_CN):
{ "code": 0,"data": {"age": 18,"name": "zhang"},"lang": "zh_CN","msg": "成功"}
英文(headers中lang=en):
{ "code": 0,"data": {"age": 18,"name": "zhang"},"lang": "en","msg": "success"}

注意

  1. headers中的lang参数值需要和msg.yaml中的语言设置一样
  2. msg.yaml中的响应状态码应和ResponseCode编码一致

总结

  • 通过定制统一返回接口,解决了项目中接口响应文本混乱的情况,提高前后端的开发效率
  • 实现了响应消息可配置化,极大的方便后续开发其他语言版本的接口
  • 实现了响应文本统一封装,减少重复代码,提高代码简洁度
  • 下一篇文章将介绍如何实现FlaskRestful响应接口封装及自定义json返回类型
  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值