🧐
フロント側とAPI側でzodを使用してバリデーションチェックをする。
はじめに
業務の中でバリデーションの定義をまとめたいと思い調べていた所
zodというライブラリがあったので使ってみました。
バリデーションスキーマの定義
import { z } from 'zod';
export const userSchema = z.object({
email: z
.string()
.min(1, { message: 'Email is required' })
.email({ message: 'Invalid email address' }),
password: z.string().min(1, { message: 'Password is required' }),
});
export type UserSchema = z.infer<typeof userSchema>;
フロント側
フロントではReact Hook Formとzodを組み合わせてバリデーションを行います。
import React from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import axios from 'axios';
import { userSchema, UserSchema } from '../../schema/';
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<UserSchema>({
resolver: zodResolver(userSchema),
});
const onSubmit: SubmitHandler<UserSchema> = (input) => {
axios
.post('http://localhost:4000/v1/user', input)
.then((response) => {
console.log(response);
})
.catch((error) => {
switch (error.response.status) {
case 400:
console.log(error.response.data);
break;
default:
console.log(error);
break;
}
});
};
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>EMAIL</label>
<input {...register('email')} />
{errors.email?.message && (
<p className="error_text">{errors.email?.message}</p>
)}
</div>
<div>
<label>PASSWORD</label>
<input {...register('password')} />
{errors.password?.message && (
<p className="error_text">{errors.password?.message}</p>
)}
</div>
<input type="submit" />
</form>
</>
);
};
export default App;
API側
ルーティングの設定などを行う。
app.ts
import express from 'express';
import cors from 'cors';
import router from './routes/v1/index';
const app = express();
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true,
optionSuccessStatus: 200,
};
app.use(cors(corsOptions));
app.use(express.json());
// ルーティング
app.use('/v1', router);
// 4000ポートで受信
const port = process.env.PORT || 4000;
// APIサーバ起動
app.listen(port);
routes/v1/index.ts
import express from 'express';
import userRouter from './user';
const router = express.Router();
// v1以下のルーティング
router.use('/user', userRouter);
export default router;
zodを使用してバリデーションを行う。
routes/v1/user.ts
import express, { Request, Response, NextFunction } from 'express';
import { ZodError, AnyZodObject } from 'zod';
import { userSchema } from '../../schema';
const router = express.Router();
const validate =
(schema: AnyZodObject) =>
async (req: Request, res: Response, next: NextFunction) => {
try {
await schema.parseAsync({ ...req.body });
return next();
} catch (error) {
if (error instanceof ZodError) {
return res.status(400).send({
error: error.flatten(),
});
}
}
};
router.post(
'/',
// バリデーションチェックが問題なければ次の処理に進む。
validate(userSchema),
(req: Request, res: Response): Response => {
return res.send('done');
},
);
export default router;
参考
Discussion
ご存知かもしれませんが言及されてなかったのでご参考までに。
バックエンドとフロントエンドで連携したい場合はtRPCという選択肢があります。
なるほどtRPCというものがあるんですね。
ありがとうございます。勉強になりました。