您如何使用 Pyramid 的 Colander 验证应用程序逻辑?
How do you validate application logic using Pyramid's Colander?
到目前为止,我正在使用漏勺验证我的 aiohttp 应用程序中的数据。
我面临的问题是我不知道如何进行"deep"验证。
给定以下架构:
import colander
class User(colander.MappingSchema):
username = colander.SchemaNode(colander.String())
password = colander.SchemaNode(colander.String())
confirmation = colander.SchemaNode(colander.String())
我都验证了输入数据结构是否包含所有必填字段(为清楚起见,限制最少)但我还需要
检查:
username
尚未被其他用户使用
password
和confirmation
是一样的
所以在我的控制器中,代码看起来像下面的伪代码:
def create_user(request):
user = await request.json()
schema = User()
# do schema validation
try:
user = schema.deserialize(user)
except colander.Invalid, exc:
response = dict(
status='error',
errors=errors.asdict()
)
return json_response(response)
else:
# check password and confirmation are the same
if user['password'] != user['confirmation']:
response = dict(
status='error'
errors=dict(confirmation="doesn't match password")
)
return json_response(response)
# check the user is not already used by another user
# we want usernames to be unique
if user_exists(user['user']):
response = dict(
status='error',
errors=dict(username='Choose another username')
)
return json_response(response)
return json_response(dict(status='ok'))
基本上有两种验证。是否可以在单个漏勺模式中同时拥有这两种逻辑?这是一个好的模式吗?
显然这是个人喜好问题,但恕我直言,最好将数据验证与应用程序逻辑分开。
您还会 运行 遇到一些试图确认用户名唯一的问题:
- Colander 需要了解您的应用程序,例如。访问数据库连接以检查该用户名不存在的数据库。
- Colander (AFAIK) 没有为 asyncio 编程设置,因此在处理检查用户是否存在的
async
方法时会遇到问题。
- 您确实希望用户创建是 ACID,因此使用相同用户名同时调用
create_user
不可能创建两个具有相同用户名的用户。
检查密码匹配是另一回事,不需要任何关于世界其他地方的知识,使用漏勺应该相当简单。我不是漏勺专家,但看起来您可以使用 deferred validator 来检查两个密码是否匹配。
关于您的代码的一些其他说明:
create_user
应该是 async
方法
- 我对你的数据库一无所知,但要从异步编程中获得任何优势
user_exists
也应该是异步的
- 用户存在性检查应包装到 ACID 用户创建中。例如。您应该使用 postgres 的
on conflict
或等价物来在创建用户时捕获重复用户,而不是先检查它们是否存在
- 为了正确 restful 并使测试更容易,您的视图应该 return 错误时的正确 http 响应代码(目前您 return 200 用于所有状态)。您应该使用 201 表示已创建,400 表示无效日期,409 或用户名冲突。
到目前为止,我正在使用漏勺验证我的 aiohttp 应用程序中的数据。
我面临的问题是我不知道如何进行"deep"验证。
给定以下架构:
import colander
class User(colander.MappingSchema):
username = colander.SchemaNode(colander.String())
password = colander.SchemaNode(colander.String())
confirmation = colander.SchemaNode(colander.String())
我都验证了输入数据结构是否包含所有必填字段(为清楚起见,限制最少)但我还需要 检查:
username
尚未被其他用户使用password
和confirmation
是一样的
所以在我的控制器中,代码看起来像下面的伪代码:
def create_user(request):
user = await request.json()
schema = User()
# do schema validation
try:
user = schema.deserialize(user)
except colander.Invalid, exc:
response = dict(
status='error',
errors=errors.asdict()
)
return json_response(response)
else:
# check password and confirmation are the same
if user['password'] != user['confirmation']:
response = dict(
status='error'
errors=dict(confirmation="doesn't match password")
)
return json_response(response)
# check the user is not already used by another user
# we want usernames to be unique
if user_exists(user['user']):
response = dict(
status='error',
errors=dict(username='Choose another username')
)
return json_response(response)
return json_response(dict(status='ok'))
基本上有两种验证。是否可以在单个漏勺模式中同时拥有这两种逻辑?这是一个好的模式吗?
显然这是个人喜好问题,但恕我直言,最好将数据验证与应用程序逻辑分开。
您还会 运行 遇到一些试图确认用户名唯一的问题:
- Colander 需要了解您的应用程序,例如。访问数据库连接以检查该用户名不存在的数据库。
- Colander (AFAIK) 没有为 asyncio 编程设置,因此在处理检查用户是否存在的
async
方法时会遇到问题。 - 您确实希望用户创建是 ACID,因此使用相同用户名同时调用
create_user
不可能创建两个具有相同用户名的用户。
检查密码匹配是另一回事,不需要任何关于世界其他地方的知识,使用漏勺应该相当简单。我不是漏勺专家,但看起来您可以使用 deferred validator 来检查两个密码是否匹配。
关于您的代码的一些其他说明:
create_user
应该是async
方法- 我对你的数据库一无所知,但要从异步编程中获得任何优势
user_exists
也应该是异步的 - 用户存在性检查应包装到 ACID 用户创建中。例如。您应该使用 postgres 的
on conflict
或等价物来在创建用户时捕获重复用户,而不是先检查它们是否存在 - 为了正确 restful 并使测试更容易,您的视图应该 return 错误时的正确 http 响应代码(目前您 return 200 用于所有状态)。您应该使用 201 表示已创建,400 表示无效日期,409 或用户名冲突。