Search code examples
typescriptexpressprismazod

How to use zod with Prisma to validate user input


I'm trying to use Zod and Prisma together and I ran into some problems with validation

in my user.model.ts file I have these validations using Zod

//user.mode.ts file

const userSchema = z.object({
  username: z.string({
    required_error: "Username field is required",
  }),
  email: z
    .string({
      required_error: "Email field is required",
      invalid_type_error: "This field must be in email format",
    })
    .email(),
  password: z
    .string({
      required_error: "Password field is required",
    })
    .min(6, "Password must be at least 6 characters"),

});

export type UserModel = z.infer<typeof userSchema>;

and in my user.service.ts file I have this one function that wants to use the validation in user.model.ts, I don't know if this is the way to use it

//user.service.ts file

export const createUser = async (
  username: string,
  email: string,
  password: string
) => {
  const user: UserModel = await prisma.user.create({
    data: {
      username: username,
      email: email,
      password: password,
    },
  });
  return user;
};

and this is how it looks like in authController.ts

//authController.ts file

export const signUpLogic = async (req: Request, res: Response) => {
  const { username, email, password } = req.body;
  try {
    const hashedPassword = await bcrypt.hash(password, 10);
    //
    createUser(username, email, String(hashedPassword));
    //

  } catch (err) {
    if (err instanceof PrismaClientKnownRequestError) {
      if (err.code === "P2002") {
        res.json({ message: "email already taken" });
      }
    }
  }
};

but when I run the code to test the validations, the terminal throws a prisma error that is supposed to be handled by the catch block instead of displaying the error message in postman.

And the validations are not working. I still can enter the wrong email format into the email field

an image of the database


Solution

  • You are forgotting to use await inside signUpLogic.

    And the validations are not working. I still can enter the wrong email format into the email field.

    You are not using zod to parse the data.

    You can do the following:

    export const createUser = async ({ 
      username,
      email,
      password,
    }: UserModel) => {
      const user: UserModel = await prisma.user.create({
        data: {
          username,
          email,
          password,
        },
      });
      return user;
    };
    
    export const signUpLogic = async (req: Request, res: Response) => {
      const { username, email, password } = req.body;
      try {
        const hashedPassword = await bcrypt.hash(password, 10);
        
        const result = userSchema.safeParse({ username, email, password: String(hashedPassword)});
    
        if(result.success) {
          await createUser(result.data);
        } else {
          // handle wrong parsing result
        }
      } catch (err) {
        if (err instanceof PrismaClientKnownRequestError) {
          if (err.code === "P2002") {
            res.json({ message: "email already taken" });
          }
        }
      }
    };