慕课网Flask构建可扩展的RESTful API-4. 理解WTForms并灵活改造她

4.1 重写WTForms

优化1

之前的代码,修改完成之后,已经修复了之前的缺陷,但是这样爆出了两个问题: 1.代码太啰嗦了,每个试图函数里,都需要这么写 2.ClientTypeError只是代表客户端类型异常,其他的参数校验不通过也抛出这个异常的话不合适

为了解决上面的问题,我们需要重写wtforms

定义一个自定义BaseForm,让其他的Form来继承

class BaseForm(Form):
def __init__(self, data):
super(BaseForm, self).__init__(data=data)

def validate_for_api(self):
valid = super(BaseForm, self).validate()
if not valid:
raise ParameterException(msg=self.errors)

以后我们的试图函数就可以这样编写

@api.route('/register', methods=['POST'])
def create_client():
data = request.json
form = ClientForm(data=data)

form.validate_for_api()
promise = {
ClientTypeEnum.USER_EMAIL: __register_user_by_email
}
promise[form.type.data]()

return 'success'

优化2

目前我们每次都需要从request中取出json信息再传入到Form对象中,优化的思路是,直接传入request,在BaseForm中取出json

优化3

每次都需要实例化Form对象,再调用validate_for_api()方法,我们可以让validate_for_api方法返回一个self对象,这样就只需要一行代码就可以解决了

class BaseForm(Form):
def __init__(self, request):
# 优化2
data = request.json
super(BaseForm, self).__init__(data=data)

def validate_for_api(self):
valid = super(BaseForm, self).validate()
if not valid:
raise ParameterException(msg=self.errors)
# 优化3
return self

优化4

操作成功也需要返回json结构,且结构应该和异常的时候一样,所以我们可以定义一个Success继承APIException

class Success(APIException):
code = 201
msg = 'ok'
error_code = 0

视图函数

@api.route('/register', methods=['POST'])
def create_client():
form = ClientForm(request).validate_for_api()
promise = {
ClientTypeEnum.USER_EMAIL: __register_user_by_email
}
promise[form.type.data]()

return Success()

我们可以接受定义时候的复杂,但是不能够接受调用的时候复杂

定义是一次性的,但是调用是多次的,如果调用太过于复杂,会使得我们的 代码太过于臃肿


4.2 全局异常处理

当系统抛出不是我们自己定义的APIException的时候,返回的结果仍然会变成一个HTML文本。

我们在写代码的过程中,有那么类型的异常: 1.已知异常:我们可以预知的。如枚举转换的时候抛出的异常,这时候我们就会提前使用try-except进行处理。也可以抛出APIException 2.未知异常:完全没有预料到的。会由框架抛出的内置异常

我们可以使用flask给我们提供的处理全局异常的装饰器,采用AOP的设计思想,捕捉所有类型的异常。

@app.errorhandler(Exception)
def framework_error(e):
if isinstance(e, APIException):
return e
if isinstance(e, HTTPException):
code = e.code
msg = e.description
error_code = 1007
return APIException(msg, code, error_code)
else:
# TODO log
if not app.config['DEBUG']:
return ServerError()
else:
raise e

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏佳爷的后花媛

java基础知识

Vector、Stack、HashTable、ConcurrentHashMap、Properties

33750
来自专栏老付的网络博客

详解.net中IL语言

中间语言,又称(IL语言)。充当Clr与.net 平台的中间语言,比如用C#编写程序,编译器首先是把C#代码转译成IL语言,最终由Clr解释执行,下面我们学习下...

20120
来自专栏偏前端工程师的驿站

(cljs/run-at (JSVM. :all) "细说函数")

前言  作为一门函数式编程语言,深入了解函数的定义和使用自然是十分重要的事情,下面我们一起来学习吧! 3种基础定义方法 defn 定义语法 (defn name...

20990
来自专栏阿杜的世界

Java Web技术经验总结(十五)

15530
来自专栏大内老A

ModelBinder——ASP.NET MVC Model绑定的核心

Model的绑定体现在从当前请求提取相应的数据绑定到目标Action方法的参数。通过前面的介绍我们知道Action方法的参数通过ParameterDescrip...

26290
来自专栏GreenLeaves

C# checked和unchecked运算符

1、作用 checked和unchecked运算符用于CLR(公共语言运行时)强制对它们所作用的代码块,进行(不进行)代码溢出检测 2、示例说明 有代码如下: ...

23680
来自专栏Redis源码学习系列

Redis源码学习之字符串对象

前文中提到,Redis的字符串对象的底层数据结构有三种,分别是整数编码、EMBSTR编码和SDS编码。在不同使用场景下进行相互切换,起到节约内存的作用。

32630
来自专栏一枝花算不算浪漫

[C#反射]C#中的反射解析及使用.

465140
来自专栏金朝麟的专栏

Module.exports和exports的区别

学习Seajs时,看到了exports.doSomething和module.exports,想对这两者的区别一探究竟。官方解释因为SeaJs和Nodejs都是...

21000
来自专栏光变

Redis持久化文件RDB的格式解析

Redis的RDB文件是对内存存储的一种表示。这个二进制文件足以完全恢复Redis当时的运行状态。 RDB文件格式针对快速读写进行了优化。LZF压缩被用于减小文...

19410

扫码关注云+社区

领取腾讯云代金券