Added zValidator wrapper for returning default error response

This commit is contained in:
sianida26 2024-05-08 00:25:41 +07:00
parent 790b9731c2
commit 199758150d
2 changed files with 103 additions and 95 deletions

View File

@ -10,6 +10,7 @@ import { hashPassword } from "../../utils/passwordUtils";
import { rolesToUsers } from "../../drizzle/schema/rolesToUsers"; import { rolesToUsers } from "../../drizzle/schema/rolesToUsers";
import { rolesSchema } from "../../drizzle/schema/roles"; import { rolesSchema } from "../../drizzle/schema/roles";
import HonoEnv from "../../types/HonoEnv"; import HonoEnv from "../../types/HonoEnv";
import requestValidator from "../../utils/requestValidator";
const userFormSchema = z.object({ const userFormSchema = z.object({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
@ -54,7 +55,7 @@ const usersRoute = new Hono<HonoEnv>()
}) })
.get( .get(
"/", "/",
zValidator( requestValidator(
"query", "query",
z.object({ z.object({
includeTrashed: z.string().default("false"), includeTrashed: z.string().default("false"),
@ -86,7 +87,7 @@ const usersRoute = new Hono<HonoEnv>()
//get user by id //get user by id
.get( .get(
"/:id", "/:id",
zValidator( requestValidator(
"query", "query",
z.object({ z.object({
includeTrashed: z.string().default("false"), includeTrashed: z.string().default("false"),
@ -144,111 +145,75 @@ const usersRoute = new Hono<HonoEnv>()
} }
) )
//create user //create user
.post( .post("/", requestValidator("form", userFormSchema), async (c) => {
"/", const userData = c.req.valid("form");
zValidator("form", userFormSchema, (result) => {
if (!result.success) { const user = await db
let errors = result.error.flatten().fieldErrors as Record< .insert(users)
string, .values({
string[] name: userData.name,
>; username: userData.username,
let firstErrors: Record<string, string> = {}; email: userData.email,
for (let field in errors) { password: await hashPassword(userData.password),
firstErrors[field] = errors[field][0]; // Grabbing the first error message for each field isEnabled: userData.isEnabled.toLowerCase() === "true",
} })
throw new HTTPException(422, { .returning();
message: JSON.stringify(firstErrors),
}); if (userData.roles) {
const roles = JSON.parse(userData.roles) as string[];
console.log(roles);
if (roles.length) {
await db.insert(rolesToUsers).values(
roles.map((role) => ({
userId: user[0].id,
roleId: role,
}))
);
} }
}),
async (c) => {
const userData = c.req.valid("form");
const user = await db
.insert(users)
.values({
name: userData.name,
username: userData.username,
email: userData.email,
password: await hashPassword(userData.password),
isEnabled: userData.isEnabled.toLowerCase() === "true",
})
.returning();
if (userData.roles) {
const roles = JSON.parse(userData.roles) as string[];
console.log(roles);
if (roles.length) {
await db.insert(rolesToUsers).values(
roles.map((role) => ({
userId: user[0].id,
roleId: role,
}))
);
}
}
return c.json(
{
message: "User created successfully",
},
201
);
} }
)
return c.json(
{
message: "User created successfully",
},
201
);
})
//update user //update user
.patch( .patch("/:id", requestValidator("form", userUpdateSchema), async (c) => {
"/:id", const userId = c.req.param("id");
zValidator("form", userUpdateSchema, (result) => { const userData = c.req.valid("form");
if (!result.success) {
let errors = result.error.flatten().fieldErrors as Record<
string,
string[]
>;
let firstErrors: Record<string, string> = {};
for (let field in errors) {
firstErrors[field] = errors[field][0]; // Grabbing the first error message for each field
}
throw new HTTPException(422, {
message: JSON.stringify(firstErrors),
});
}
}),
async (c) => {
const userId = c.req.param("id");
const userData = c.req.valid("form");
const user = await db const user = await db
.select() .select()
.from(users) .from(users)
.where(and(eq(users.id, userId), isNull(users.deletedAt))); .where(and(eq(users.id, userId), isNull(users.deletedAt)));
if (!user[0]) return c.notFound(); if (!user[0]) return c.notFound();
await db await db
.update(users) .update(users)
.set({ .set({
...userData, ...userData,
...(userData.password ...(userData.password
? { password: await hashPassword(userData.password) } ? { password: await hashPassword(userData.password) }
: {}), : {}),
updatedAt: new Date(), updatedAt: new Date(),
isEnabled: userData.isEnabled.toLowerCase() === "true", isEnabled: userData.isEnabled.toLowerCase() === "true",
}) })
.where(eq(users.id, userId)); .where(eq(users.id, userId));
return c.json({ return c.json({
message: "User updated successfully", message: "User updated successfully",
}); });
} })
)
//delete user //delete user
.delete( .delete(
"/:id", "/:id",
zValidator( requestValidator(
"form", "form",
z.object({ z.object({
skipTrash: z.string().default("false"), skipTrash: z.string().default("false"),

View File

@ -0,0 +1,43 @@
import { zValidator } from "@hono/zod-validator";
import DashboardError from "../errors/DashboardError";
type ValidatorParameters = Parameters<typeof zValidator>;
/**
* Creates a request validator using the Zod schema.
* This middleware function is designed for use with the Hono framework to validate incoming requests.
* If the validation fails, it throws a `DashboardError` with detailed information about the validation errors.
*
* @param parameters - Parameters expected by `zValidator`. The first parameter is the Zod schema,
* the second is options for the Zod validator, and the third is a custom error handler.
* @returns A middleware function that validates the request against the provided schema.
*/
const requestValidator = (...parameters: ValidatorParameters) => {
return zValidator(
parameters[0],
parameters[1],
parameters[2] ??
((result) => {
if (!result.success) {
let errors = result.error.flatten().fieldErrors as Record<
string,
string[]
>;
let firstErrors: Record<string, string> = {};
for (let field in errors) {
firstErrors[field] = errors[field][0]; // Grabbing the first error message for each field
}
throw new DashboardError({
errorCode: "INVALID_FORM_DATA",
message:
"Validation failed. Please check your input and try again.",
formErrors: firstErrors,
severity: "LOW",
statusCode: 422,
});
}
})
);
};
export default requestValidator;