fix: update Request validation/tests for Employee FK relation
- createRequestSchema now requires employee_id to be a UUID-format string (was a free-text non-empty check), matching the new FK to Employee in schema.prisma. - createRequest() now returns a CreateRequestResult discriminated union and catches Prisma P2003 (FK violation), returning a friendly ok:false error instead of a raw 500 when employee_id does not reference an existing Employee. POST /api/requests branches on created.ok and returns 400 in that case. - tests/requests.test.ts: every test that used to POST a fake string employee_id (emp-1, emp-2) now creates a real Employee first via createTestEmployee() and uses its id, since employee_id is now a real FK. Added coverage for a syntactically invalid UUID and for a well-formed but non-existent UUID (expects the friendly 400 from the P2003 catch, not a raw 500) - the exact case this retrofit was meant to protect against.
This commit is contained in:
@@ -32,7 +32,11 @@ export async function POST(request: Request): Promise<NextResponse> {
|
||||
}
|
||||
|
||||
const created = await createRequest(validation.value);
|
||||
return NextResponse.json(created, { status: 201 });
|
||||
if (!created.ok) {
|
||||
return NextResponse.json({ error: created.error }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json(created.value, { status: 201 });
|
||||
}
|
||||
|
||||
export async function GET(): Promise<NextResponse> {
|
||||
|
||||
+36
-10
@@ -1,4 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { prisma } from "./prisma";
|
||||
|
||||
export type RequestType = "asset" | "license";
|
||||
@@ -40,7 +41,14 @@ function nonEmptyString(message: string) {
|
||||
}
|
||||
|
||||
const createRequestSchema = z.object({
|
||||
employee_id: nonEmptyString("employee_id is required and must be a non-empty string"),
|
||||
// Now a real FK to Employee (see schema.prisma) — only a UUID *format*
|
||||
// check here — whether it references a real employee is left to Prisma's
|
||||
// own FK constraint at insert time (see createRequest()'s P2003 handling
|
||||
// below), rather than an extra pre-check query. Mirrors the same pattern
|
||||
// used for Employee.managerId in src/lib/employees.ts.
|
||||
employee_id: z
|
||||
.string({ required_error: "employee_id is required and must be a valid UUID string" })
|
||||
.uuid("employee_id is required and must be a valid UUID string"),
|
||||
reason: nonEmptyString("reason is required and must be a non-empty string"),
|
||||
type: z.enum(["asset", "license"], {
|
||||
errorMap: () => ({
|
||||
@@ -85,15 +93,33 @@ function toRecord(row: {
|
||||
};
|
||||
}
|
||||
|
||||
export async function createRequest(input: CreateRequestInput): Promise<RequestRecord> {
|
||||
const created = await prisma.request.create({
|
||||
data: {
|
||||
employeeId: input.employee_id,
|
||||
type: input.type,
|
||||
reason: input.reason,
|
||||
},
|
||||
});
|
||||
return toRecord(created);
|
||||
export type CreateRequestResult =
|
||||
| { ok: true; value: RequestRecord }
|
||||
| { ok: false; error: string };
|
||||
|
||||
/**
|
||||
* Creates a Request. If employee_id doesn't reference an existing Employee,
|
||||
* Prisma raises a known error (code P2003, FK violation) — caught here and
|
||||
* translated into the same `{ok:false,error}` shape as input validation
|
||||
* failures, rather than letting a raw Prisma error leak to the API layer.
|
||||
* Mirrors src/lib/employees.ts's createEmployee() pattern for managerId.
|
||||
*/
|
||||
export async function createRequest(input: CreateRequestInput): Promise<CreateRequestResult> {
|
||||
try {
|
||||
const created = await prisma.request.create({
|
||||
data: {
|
||||
employeeId: input.employee_id,
|
||||
type: input.type,
|
||||
reason: input.reason,
|
||||
},
|
||||
});
|
||||
return { ok: true, value: toRecord(created) };
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2003") {
|
||||
return { ok: false, error: "employee_id does not reference an existing employee" };
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function listRequests(): Promise<RequestRecord[]> {
|
||||
|
||||
Reference in New Issue
Block a user