Validasi Request API menggunakan Zod
Ketika membuat service API salah satu hal yang wajib banget dilakuin yaitu melakukan validasi pada request data. Kenapa harus di validasi ya karena biasanya logic service yang kita bikin itu perlu data dengan format tertentu, mungkin ada field yang required, field nya harus pake tipe data tertentu atau harus sesuai dengan format yang valid contohnya email dan nomor KTP.
Kalau kalian udah familiar di dunia perkodingan typescript, entah di frontend ataupun backend pasti udah ngga asing lagi sama library yang namanya "Zod". Kayaknya Zod ini udah jadi library buat schema validation yang paling populer di kalangan developer Javascript/Typescript karena emang cara pake nya itu simple banget cuy. Library ini biasanya dipake buat validasi form di frontend tapi sebenernya masih banyak kegunaan lainnya, salah satunya dan merupakan topik yang mau kita bahas yaitu kita pake Zod sebagai middleware di express.js untuk melakukan validasi request data.
Zod is designed to be as developer-friendly as possible. The goal is to eliminate duplicative type declarations. With Zod, you declare a validator once and Zod will automatically infer the static TypeScript type. It's easy to compose simpler types into complex data structures.
Setup Project Dulu
Kita siapin folder terus init projectnya:
mkdir express-zod-ts && cd express-zod-ts
npm init -y
Lanjut install dependency:
npm install express zod
npm install --save-dev typescript @types/express ts-node nodemon
Dependency yang kita pake disini basic aja ya, ada express buat server, zod buat validasi, typescript dan nodemon buat running server nya.
Pasang nodemon ke script di package.json:
/* package.json */
{
"scripts": {
"dev": "nodemon src/server.ts"
}
}
Karena kita pake typescript jangan lupa buat init config nya:
npx tsc --init
Buat config nya kita juga setting basic aja ya:
/* tsconfig.json */
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
}
}
Sip, setup nya udah beres kita lanjut ke step berikutnya!
Bikin Middleware Buat Validasi
Kita bikin yang simpel simpel aja buat contoh disini kita akan bikin validasi untuk registrasi user.
Pertama buat schema nya dulu:
/* src/schema/userSchema.ts */
import { z } from "zod";
export const userSchema = z.object({
name: z.string().min(3, "Name must be at least 3 characters long"),
email: z.string().email("Invalid email format"),
password: z.string().min(6, "Password must be at least 6 characters"),
});
export type UserInput = z.infer<typeof userSchema>;
Disini kita buat schema user dengan 3 field yang punya validasi nya masing-masing. Kita juga bisa infer schema nya yang nanti bisa kita gunakan sebagai data type.
Lanjut bikin zod reusable middleware:
/* src/middleware/validate.ts */
import { Request, Response, NextFunction } from "express";
import { ZodSchema } from "zod";
export const validate =
(schema: ZodSchema) => (req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.errors });
}
next();
};
Function validate ini nanti memvalidasi request body berdasarkan zod schema tertentu. Jika validasi gagal kita return error 400, kalau berhasil maka kita panggil function next()
yang artinya request sukses melewati middleware ini dan lanjut ke function berikutnya.
Express API
Sekarang kita buat Express App nya:
/* src/server.ts */
import express, { Request, Response } from "express";
import { userSchema, UserInput } from "./userSchema";
import { validate } from "./validate";
const app = express();
app.use(express.json());
app.post("/register", validate(userSchema), (req: Request, res: Response) => {
const user: UserInput = req.body;
res.json({ message: "User registered successfully!", user });
});
const PORT = 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Disini kita bikin endpoint register yang manggil middleware validate kita tadi dan passing userSchema untuk validasi request body nya. Kemudian app nya akan kita running di port 3000. Aplikasi kita siap di running pake command:
npm run dev
Testing
Setelah semua persiapan selesai dan aplikasi kita udah running, sekarang saat nya kita testing API yang udah kita buat.
Testing ketika format request body sesuai dengan schema:
curl -X POST http://localhost:3000/register \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "john@example.com", "password": "secure123"}'
{
"message": "User registered successfully!",
"user": {
"name": "John Doe",
"email": "john@example.com",
"password": "secure123"
}
}
Response error ketika tidak sesuai:
curl -X POST http://localhost:3000/register \
-H "Content-Type: application/json" \
-d '{"name": "Jo", "email": "john@example.com", "password": "secure123"}'
{
"errors": [
{
"path": ["name"],
"message": "Name must be at least 3 characters long",
"code": "too_small"
}
]
}
Dengan pake reusable middleware kayak gini kita ga perlu lagi validasi manual case by case nya dan bisa bikin API kita clean, maintainable dan type-safe.