Server Actions(Next13)で使用しているyupのtestで値の重複チェックをする
前回まで
Server Actionsでreact-hookformとyupを作って簡易なユーザー登録フォームを作った。
登録を作ったのでログインも作ろうと思い、前回簡素に作っていたため実装していなかったメールアドレスの重複チェックやパスワードのハッシュ化を書いているときにふと思った。
「yupのバリデーションでメールアドレスの重複チェックできるのでは……?」
これができると
バリデーション(フロント) -> バリデーション(バックエンド) -> 返却されたエラーメッセージをフロントで表示
この流れをバリデーション一本で実装できるようになる。
= データ登録の処理が簡略化されるメリットを期待。
やってみた
流れと実装方法
Submitのタイミングでバリデーションを走らせているのでそこで重複チェックをしたい。
yupにtest()
があるのでそれを使用する。
前回のコード
前回の記事ではバリデーションの内容に重きをおいてなかったので割愛していた。
import * as yup from 'yup'
export type UserProp = 'name' | 'email' | 'password'
export type User = {
name: string
email: string
password: string
}
export const userSchema = yup.object().shape({
name: yup.string().required('必須項目です'),
email: yup.string().email('メールアドレスを入力してください').required('必須項目です'),
password: yup.string().min(8, '8文字以上で入力してください').required('必須項目です'),
})
実装
重複チェックの関数作成
hooksに置きたいので前回作成したhooksに追記する。
'use server'
import { hashSync } from 'bcrypt'
import prisma from '~/lib/prisma'
// 追記
export const validationEmail = async (email: string) => {
'use server'
const check = await prisma.users.findFirst({
where: { email: email },
})
if (check) return false
return true
}
// 追記終わり
export const createUser = async (data: { name: string; email: string; password: string }) => {
'use server'
console.log(data)
const hashPath = hashSync(data.password, 10)
await prisma.user.create({ data: { ...data, password: hashPath } })
return true
}
yupのtest()
はfalse
でエラーにしてくれるので、入力したemailを使用しているユーザーが見つかった場合にfalse
を返す形に作成。
yupのコードに追加
import * as yup from 'yup'
import { validationEmail } from '~/features/user/hooks/create'
export type UserProp = 'name' | 'email' | 'password'
export type User = {
name: string
email: string
password: string
}
export const userSchema = yup.object().shape({
name: yup.string().required('必須項目です'),
email: yup
.string()
.email('メールアドレスを入力してください')
.required('必須項目です')
.test('email', 'メールアドレスはすでに使用されています。', (value) => validationEmail(value)),
password: yup.string().min(8, '8文字以上で入力してください').required('必須項目です'),
})
これで入力したメールアドレスが重複していたら該当のエラーメッセージを出力してくれる。
バリデーション走らせてみる
example@example.com
のメールアドレスを重複させる。
一人目作成。
二人目作成
同じアドレスを入力してボタンぽち。
できるなぁ……。
DBにも追加されなかった。
やってみて
結論:
yupのバリデーションでDB内の値の重複チェックができる。
今までDBの値を比較したりというフロント側でできなかったバリデーションの一本化ができる。
バックエンドの返却値を使ってエラーを表示させる必要もないので、登録処理がシンプルになるという期待通りの結果になった。
余談
簡単にパスワードのハッシュ化もしれっと追加した。
bcrypt
を使用。
// 省略
export const createUser = async (data: { name: string; email: string; password: string }) => {
'use server'
console.log(data)
const hashPath = hashSync(data.password, 10)
await prisma.user.create({ data: { ...data, password: hashPath } })
return true
}
Discussion