A subtle, dangerous bug: blindly spreading the request body into your database write.
1const body = await req.json();
2await prisma.user.update({ where: { id }, data: body }); // 😱A user submits:
1{ "name": "Mallory", "role": "ADMIN", "isVerified": true }They just promoted themselves to admin. This is mass assignment (a.k.a. over-posting): the client sets fields they were never supposed to touch.
1const UpdateProfile = z.object({
2 name: z.string().max(100).optional(),
3 bio: z.string().max(500).optional(),
4}); // role, isVerified, id simply aren't here
5
6const data = UpdateProfile.parse(body);
7await prisma.user.update({ where: { id }, data });Unknown fields are dropped. role can never be set through this endpoint.
1const { name, bio } = body;
2await prisma.user.update({ where: { id }, data: { name, bio } });Some fields must never come from the client:
| Field | Who sets it |
|---|---|
id | The database |
ownerId / userId | The session |
role, isVerified | Admin flows only |
createdAt, updatedAt | The database |
price (in a checkout) | The server, from the catalog |
The rule from Chapter 5 generalizes: derive identity and privilege fields on the server, never from the request body.