Как вы проверяете логику приложения, используя пирамидальный дуршлаг?
До сих пор я использую дуршлаг для проверки данных в моем приложении aiohttp.
Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю, как сделать "глубокую" проверку.
Дана следующая схема:
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'))
В основном существует два вида проверки. Можно ли иметь обе логики в схеме одного дуршлаг? Это хороший шаблон?
1 ответ
Очевидно, что это дело вкуса, но ИМХО лучше держать проверку данных отдельно от логики приложения.
Вы также столкнетесь с несколькими проблемами, пытаясь подтвердить, что имя пользователя уникально:
- Дуршлаг должен иметь знания о вашем приложении, например. получить доступ к соединению с базой данных, чтобы проверить с базой данных, что это имя пользователя не существует.
- Colander (AFAIK) не настроен для асинхронного программирования, поэтому у него будут проблемы с
async
метод, который проверяет пользователя, существует. - Вы действительно хотите, чтобы создание пользователя было ACID, поэтому одновременные вызовы
create_user
с одним и тем же именем пользователя невозможно создать двух пользователей с одним и тем же именем.
Проверка соответствия паролей - это еще одна история, которая не требует никаких знаний об остальном мире и должна быть довольно тривиальной с дуршлагом. Я не специалист по дуршлагу, но похоже, что вы можете использовать отложенный валидатор для проверки совпадения двух паролей.
Несколько других примечаний к вашему коду:
create_user
должен бытьasync
метод- Я ничего не знаю о вашей БД, но чтобы получить какое-либо преимущество от асинхронного программирования
user_exists
тоже должен быть асинхронным - Проверка существования пользователя должна быть включена в создание пользователя ACID. Например. Вы должны использовать Postgres's
on conflict
или эквивалент, чтобы поймать дубликата пользователя при его создании, а не проверять, существует ли он первым - Чтобы быть спокойным и упростить тестирование, ваше представление должно вернуть правильный http-код ответа на ошибку (в настоящее время вы возвращаете 200 для всех состояний). Вы должны использовать 201 для созданного, 400 для недействительной даты и 409 или конфликт имени пользователя.