null hay bỏ qua trường
Kết luận: `null` nói rằng trường tồn tại nhưng không có giá trị; bỏ qua trường nói rằng trường không tồn tại. Thân PATCH, gộp cấu hình và điền sẵn biểu mẫu là nơi sự khác biệt này gây ra vấn đề.

Tóm lại: hãy gửi null khi bên tiêu thụ phải phân biệt "đã xóa" với "chưa đụng tới" — trong thân PATCH, bỏ qua để nguyên trường còn null tường minh thì xóa nó — và giữ một quy ước cho mỗi trường để phản hồi và gộp cấu hình luôn ổn định.
Sự khác biệt
{ "nickname": null }
Có mặt, rỗng. Bên tiêu thụ biết trường đã bị xóa một cách tường minh.
{ }
Vắng mặt. Bên tiêu thụ không phân biệt được "chưa từng đặt" với "không được hỗ trợ".
Trong JavaScript, sự phân biệt này rất cụ thể:
'nickname' in obj // false — absent
obj.nickname === null // true — present and null
obj.nickname === undefined // true — both cases
Nơi nào quan trọng
Thân PATCH. {"nickname": null} xóa nickname. {} không thay đổi gì. Nếu handler coi "null" và "thiếu" là như nhau, người dùng sẽ không bao giờ xóa được trường — họ chỉ có thể đặt chuỗi rỗng, mà đó là chuyện khác.
Hãy cài đặt dựa trên sự tồn tại của khóa, không dựa trên giá trị:
if (Object.hasOwn(patch, 'nickname')) {
target.nickname = patch.nickname; // null allowed
}
Gộp cấu hình. Bỏ qua sẽ kế thừa giá trị mặc định; null tắt nó một cách tường minh. Đây chính là cách giá trị của Helm và Kubernetes hành xử.
Điền sẵn biểu mẫu. Một null hiển thị thành rỗng, trường thiếu cũng vậy, nhưng khi gửi thì khác nhau: đã có giá trị, nay bị xóa → gửi null; chưa từng điền → bỏ qua. Thiếu sự phân biệt này, việc xóa trông y hệt việc không đụng tới.
Quy ước
| Tình huống | Quy ước |
|---|---|
| Thân phản hồi | Giữ null; cấu trúc ổn định, kiểu đơn giản hơn |
| Yêu cầu PATCH | null xóa, vắng mặt giữ nguyên |
| PUT (thay thế toàn bộ) | Bỏ qua nghĩa là xóa — toàn bộ tài liệu bị thay thế |
| Gộp cấu hình | Bỏ qua = mặc định, null = tắt |
| Cơ sở dữ liệu | null cho chưa biết hoặc không áp dụng; '' cho đã biết là rỗng |
Giữ cấu trúc phản hồi ổn định. Một danh sách mà vài phần tử có avatar còn vài phần tử không sẽ buộc mọi nơi gọi phải kiểm tra 'avatar' in item. avatar: null dễ tiêu thụ hơn.
Ba điều không nên làm
Đừng dùng "" thay cho null. Nickname rỗng và nickname chưa đặt là hai trạng thái khác nhau trong hầu hết lĩnh vực.
Đừng dùng 0 hay -1 làm giá trị đánh dấu. Số không là một con số hợp lệ, và giá trị đánh dấu sẽ làm hỏng mọi phép trung bình bạn tính.
Đừng trộn quy ước giữa các endpoint. Hai quy ước nghĩa là hai nhánh mã trong mọi client.
Câu hỏi thường gặp
Điều gì quyết định giữa null và trường bị bỏ qua?
Hãy hỏi xem bên tiêu thụ có cần phân biệt "đã xóa tường minh" với "chưa từng đặt" hay không. Trong thân PATCH thì bắt buộc phân biệt, nên null xóa còn vắng mặt giữ nguyên; trong phản hồi, giữ null giúp cấu trúc ổn định và kiểu phía client đơn giản hơn.
Endpoint PATCH phân biệt việc xóa với việc để nguyên bằng cách nào?
Kiểm tra sự tồn tại của khóa chứ không phải giá trị: Object.hasOwn(patch, 'nickname') cho biết trường đã được gửi, và chỉ khi đó mới gán, kể cả null. Nếu handler coi null và thiếu là như nhau, người dùng sẽ không bao giờ xóa được trường mà chỉ có thể rơi về chuỗi rỗng.
Vì sao thân phản hồi nên giữ null?
Cấu trúc ổn định nghĩa là client không cần kiểm tra 'avatar' in item cho mọi khóa tùy chọn. Khi vài phần tử trong danh sách có avatar còn vài phần tử bỏ qua, phép kiểm tra đó bị lặp ở mọi nơi gọi và rất dễ sai.