Both update a resource, but they make different promises.
PUT says "here is the complete new state of the resource." Fields you omit are reset to defaults or null.
PUT /tasks/42
{ "title": "New title", "status": "TODO" }
If the task had a dueDate, a strict PUT clears it because you didn't include it. PUT is idempotent — sending it twice yields the same result.
PATCH says "merge these changes into the existing resource." Omitted fields are left alone.
PATCH /tasks/42
{ "status": "DONE" }
Only status changes; title and dueDate stay. This is what users usually expect from an "edit" form that submits one field.
In practice, PATCH is the workhorse. Most UIs edit a subset of fields. Offer PUT when a client genuinely wants to overwrite the whole object (e.g. a settings document).
With Zod, derive a partial schema so every field becomes optional — but require at least one:
1const PatchTask = CreateTask.partial().refine(
2 (obj) => Object.keys(obj).length > 0,
3 { message: "Provide at least one field to update" },
4);1export async function PATCH(req, { params }) {
2 const { id } = await params;
3 const session = await requireSession();
4
5 const parsed = PatchTask.safeParse(await req.json());
6 if (!parsed.success) return badRequest(parsed.error);
7
8 // Authorize: only the owner may update
9 const existing = await prisma.task.findUnique({ where: { id } });
10 if (!existing || existing.ownerId !== session.userId) return notFound();
11
12 const task = await prisma.task.update({
13 where: { id },
14 data: parsed.data, // updatedAt is bumped automatically
15 });
16 return NextResponse.json({ data: task });
17}