NSF Back-end Dev Engineer

后端框架

2023-05-12
nsf

python后端框架相关内容

1.简介

下面以django为例,介绍比较完整的后端框架应该完成的工作

日常大部分接口主要需要考虑实现的是5,6,7步,主要需要实现的内容为

  • 异常处理
  • 参数校验
  • 接口逻辑处理
  • 数据库操作

其他我们需要思考的还有路由,view层,service层,model层,这些基本上结构都是由文件夹结构来分层次,一般按app分,下面是一个例子:

project:
	apps:
		test1:
			services:
				test1_service.py
			views:
				test_view.py
			apps.py
			dao.py
			forms.py
			models.py
			serilizers.py
			urls.py
	project:
		asgi.py
		setting.py
		urls.py
		wsgi.py
	tools:
		api_req.py
		api_req_code.py
		base_error.py
		validator_utils.py

一个接口的例子如下:

class Test1View(APIView):
    @api_req_param(form=forms.Test1GetSerializer)
    def get(self, request):
        req_data = request.req_data
        service = Test1Service()

        res = service.get_spend_time()

        return {'a': req_data.get('a', None), 'b': req_data['b'], 'res': res}

Test1GetSerializer实现如下:

class Test1GetSerializer(CleanSerializer):
    a = serializers.CharField(required=False, min_length=3)
    b = serializers.EmailField(required=True, validators=[CleanValidator(key='str_prefix', prefix='abc')])

api_req_param实现包含异常处理和参数校验,异常处理在最顶层,代码如下:

def api_req_param(req_data='GET', form=serializers.Serializer):
    def api_req_param_decorator(func):
        _post_code2 = get_post_code2(inspect.getsourcefile(func))

        @api_req(_post_code2)
        @api_param(req_data=req_data, form=form)
        @wraps(func)
        def wrapped_func(*args, **kwargs):
            return func(*args, **kwargs)

        return wrapped_func

    return api_req_param_decorator

2.异常处理

异常处理放置在最顶层的好处是能捕获全局所有异常,代码中可以用raise XXX的形式来随时中断程序抛出异常

关于异常处理重点包含:

  • 异常码定义
  • 各种异常定义

异常处理代码如下:

def api_req(post_code2=None):
    def api_req_decorator(func):
        @wraps(func)
        def wrapped_func(self, request, *args, **kwargs):
            self.post_code2 = model_code_dict.get(post_code2, 'XX')
            err_resp = ErrResponse(self.post_code2)
            try:
                res = func(self, request, *args, **kwargs)
                return Response({'code': '0000', 'data': res, 'message': 'success'})
            except BaseError as base_e:
                return Response(err_resp.get_err_res(base_e.code1, base_e.message, base_e.code3))
            except Exception as e:
                return Response(err_resp.get_err_res('X', str(e), 'X'))

        return wrapped_func

    return api_req_decorator
    
class ErrResponse:
    def __init__(self, post_code2='XX'):
        self.post_code2 = post_code2

    def get_err_res(self, code1='X', message='', code3='0'):
        return {'code': code1 + self.post_code2 + code3, 'data': {}, 'message': message}

2.1.异常码定义

关于异常码这里只举一个例子:

  • 四位构成
  • code1:第一位为异常分类,比如参数校验异常,数据库连接异常等
  • code2:第二位和第三位定义异常模块,说明这个异常出自哪个模块
  • code3:第四位为异常详情
  • message:除了异常码同时还有一个异常详情message字段说明异常详情
code1_dict = {
    'OK': ('0', 'success'),
    'ErrorParam': ('1', 'input param is wrong')
}

model_code_dict = {'apps.test1': '00'}

code2由程序自动获取,代码如下:

def get_post_code2(path):
    path = path.replace('\\', '/')
    path_l = path.split('/apps/')
    if len(path_l) == 1:
        return None

    i = path_l[1].find('/')
    path = 'apps.' + path_l[1][:i] + '.apps'
    module = importlib.import_module(path)
    for name, cls in inspect.getmembers(module, inspect.isclass):
        post_code2 = getattr(cls, 'name', None)
        if post_code2 is not None:
            return post_code2

    return None

2.2.异常定义

代码如下:

class BaseError(Exception):
    def __init__(self, message, code1='unknown', code3='0'):
        self.message = message
        if code1_dict.get(code1, None) is None:
            self.code1 = 'X'
        else:
            self.code1 = code1_dict[code1][0]
        self.code3 = code3


class ParamError(BaseError):
    def __init__(self, message, code3='0'):
        super().__init__(message, 'ErrorParam', code3)

3.参数校验

代码如下:

def api_param(req_data='GET', form=serializers.Serializer):
    def api_param_decorator(func):
        @wraps(func)
        def wrapped_func(self, request, *args, **kwargs):
            try:
                data = form(data=getattr(request, req_data))
                data.is_valid(raise_exception=True)
            except Exception as e:
                logging.getLogger(__name__).error(f'parameter error {e!s}')
                raise ParamError(str(e))

            request.req_data = data.data
            return func(self, request, *args, **kwargs)

        return wrapped_func

    return api_param_decorator

除了全局校验可以自定义校验类:

class CleanValidator:
    code = 'invalid'

    def __init__(self, key, *args, **kwargs):
        self.key = key
        self.args = args
        self.kwargs = kwargs

    @staticmethod
    def clean_str_prefix(value, prefix=''):
        if not value.startswith(prefix):
            raise ValidationError(f'{value!s}\'s prefix should equal {prefix!s}')

    def __call__(self, value):
        handler = getattr(self, 'clean_' + self.key, None)
        if handler is None:
            raise ValidationError(f'you need achieve your method about {self.key}', code=self.code)
        return handler(value, *self.args, **self.kwargs)


class CleanSerializer(serializers.Serializer):

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

4.接口逻辑处理

接口逻辑具体实现在service中:

class Test1Service:
    def __init__(self):
        self.start_time = time()

    def get_spend_time(self):
        return time() - self.start_time

5.数据库操作

数据库操作可以统一放在dao.py中,或者如果数据库操作已经封装得比较好了(ORM),也可以考虑放在service中


Similar Posts

上一篇 python

下一篇 python-demo集合

Comments