目次
7日目 - バリデーションの追加
各Modelのバリデーションを追加し、それぞれのエラーハンドリングを適応させていく。
Userモデルのバリデーション
api/v1/models/user.py
# ~~~
from sqlalchemy.orm import relationship,validates
# ~~~
@validates("login_id")
def check_user_login_id(self,key,v):
if v == None:
raise ValueError("LoginId must not be null")
if v == "":
raise ValueError("LoginId must not be empty string")
if not v.replace('-','').replace('_','').isalnum():
raise ValueError("LoginId can only contain letters, numbers, _, and -")
if v[0] == "-" or v[0] == "_":
raise ValueError('LoginId cannot start with _ or -')
return v
@validates("name")
def check_user_name(self,key,v):
if v == None:
raise ValueError("Name must not be null")
if v == "":
raise ValueError("Name must not be empty string")
return v
# ~~~
ただこの場合、passwordはモデルに入るときにはhashにされてしまうのでここではバリデーションできない。
なので一旦crudsファイル内でバリデーションする。(絶対もっといい方法がある。。。)
api/v1/cruds/user.py
# ~~~~
def create_user(db:Session,user:user_schema.UserCreateRequest):
if len(user.password) < 8:
raise ValueError("Password require at least 8 characters")
if not user.password.isalnum():
raise ValueError("Password can only contain letters, numbers")
password_hash = get_password_hash(user.password)
new_user = User(
login_id=user.login_id,
name=user.name,
description=user.description,
password_hash=password_hash
)
# ~~~~
これで各部でバリデーションによるエラーを起こすところまでできたので、あとはこのエラーをルーター部分でキャッチする。
api/v1/routers/user.py
# ~~~
@router.post('/users',response_model=user_schema.User)
def create_user(user:user_schema.UserCreateRequest,db:Session = Depends(get_db)):
db_user = user_crud.get_user_by_login_id(db,user.login_id)
if db_user:
raise HTTPException(status_code = 400,detail = "LoginId already exists")
try:
new_user = user_crud.create_user(db,user)
except ValueError as e :
raise HTTPException(status_code = 400,detail = str(e))
return new_user
# ~~~
これでバリデーションに引っかかった場合も400でエラー内容を返すことができる。
pydanticでもバリデーションが行えるので、そっちにもバリデーションを追加しておくとより良いかも。
とりあえずこれでbackend側の構築はOK。(足りない場合も今までの実装方法で対応できる。。はず。。。)
次からはフロントエンドを作っていくが、Next.jsを利用した構築にチャレンジしてみようと思うので、次回はまた時間がかかりそう。