Tìm hiểu về chuẩn JSON Merge Patch cùng Hằng béo

Tìm hiểu về chuẩn JSON Merge Patch cùng Hằng béo

-- Anh Tèo này, dạo này em hay làm với Fredrik, thấy hắn code sáng ghê.

-- Code như nào mà sáng?

-- README viết rất , code có design pattern rõ ràng, comment đầy đủ. Ngoài ra còn đúng chuẩn nữa.

-- Chuẩn? Chuẩn gì?

-- Ví dụ gần nhất là chuẩn RFC7396: JSON Merge Patch

Tóm tắt kiến thức

  • RFC 7396 là một tiêu chuẩn của IETF (Internet Engineering Task Force) đặc biệt liên quan đến việc thay đổi các tài nguyên JSON bằng cách sử dụng các tài liệu JSON nhỏ được gọi là JSON Patch
  • RFC = "Request for Comments", có nghĩa là "Yêu cầu ý kiến" hoặc "Đề nghị ý kiến." Cụ thể, trong ngữ cảnh của IETF (Internet Engineering Task Force), RFC là một loạt các tài liệu mà những người tham gia đưa ra để mô tả, đề xuất hoặc đánh giá các tiêu chuẩn, giao thức, quy trình và các vấn đề liên quan đến phát triển và quản lý Internet
  • Bạn hiểu đơn giản là quy ước để update JSON
    • Mục tiêu sinh ra quy ước để có 1 cái chuẩn, cả thế giới làm theo, tránh mỗi ông mỗi kiểu.
  • RFC 7396 quy ước muốn cập nhật field nào thì gửi field đó lên thôi, tránh gửi toàn bộ lên, tốn băng thông.
  • Về cơ bản thì có các nguyên tắc sau:
    • Chỉ gửi field nào cần update lên
    • Nếu field nào chưa có trong object gốc ~> thêm vào
    • Nếu field nào có trong object gốc rồi ~> thay thế
    • Nếu field nào mà value là null ~> xóa field đi
    • Method là PATCH, Content-Type là application/merge-patch+json
  • Danh sách đầy đủ các test cases:
ORIGINAL        PATCH            RESULT
   ------------------------------------------
   {"a":"b"}       {"a":"c"}       {"a":"c"}

   {"a":"b"}       {"b":"c"}       {"a":"b",
                                    "b":"c"}

   {"a":"b"}       {"a":null}      {}

   {"a":"b",       {"a":null}      {"b":"c"}
    "b":"c"}

   {"a":["b"]}     {"a":"c"}       {"a":"c"}

   {"a":"c"}       {"a":["b"]}     {"a":["b"]}

   {"a": {         {"a": {         {"a": {
     "b": "c"}       "b": "d",       "b": "d"
   }                 "c": null}      }
                   }               }

   {"a": [         {"a": [1]}      {"a": [1]}
     {"b":"c"}
    ]
   }

   ["a","b"]       ["c","d"]       ["c","d"]

   {"a":"b"}       ["c"]           ["c"]

   {"a":"foo"}     null            null

   {"a":"foo"}     "bar"           "bar"

   {"e":null}      {"a":1}         {"e":null,
                                    "a":1}

   [1,2]           {"a":"b",       {"a":"b"}
                    "c":null}

   {}              {"a":            {"a":
                    {"bb":           {"bb":
                     {"ccc":          {}}}
                      null}}}

Chém

-- Anh cũng chưa nghe tới cái chuẩn này bao giờ. Nghe nguy hiểm nhỉ. Mày tóm tắt trong mười lăm chữ đi xem có gì hot nào?

-- Về cơ bản, nó là chuẩn để anh update JSON.

-- Update JSON? Bình thường anh thấy đội dev gửi cả cục lên, replace là xong mà?

-- Đúng là vậy. Tuy nhiên việc gửi toàn bộ JSON lên sẽ làm tốn băng thông. JSON bé không sao, JSON to tốn cả Kb chứ chẳng chơi. Một ngày vài triệu tới vài trăm triệu request, anh có biết nó nhiều thế nào không?

-- Ừ nhỉ. Nghe mày nói, anh thấy nó cũng... to to. Thế nói rõ hơn về chuẩn đi.

-- Chuẩn JSON Merge Patch, hay còn gọi là RFC 7396, quy ước một số nguyên tắc sau khi update JSON value

  • Chỉ gửi field nào cần update lên
  • Nếu field nào chưa có trong object gốc ~> thêm vào
  • Nếu field nào có trong object gốc rồi ~> thay thế
  • Nếu field nào mà value là null ~> xóa field đi
  • Method là PATCH

-- Nghe hơi lí thuyết. Anh nghĩ nên có vài ví dụ?

-- Ví dụ thế này: giả sử ban đầu, file JSON của em trông như sau:

{
     "title": "From Hang xinh gai with love",
     "author" : {
       "givenName" : "Hang",
       "familyName" : "Xinh Gai"
     },
     "tags":[ "girl_pho", "girl_thu_do" ],
     "content": "A girl, who love Go programming"
   }

Giả sử em muốn xóa familyName đi, thay content thành: "Hang xinh gai sieu cap vjp pr0" thì em sẽ gửi patch request với nội dung như sau:

PATCH /my/resource HTTP/1.1
   Host: example.org
   Content-Type: application/merge-patch+json
 
   {
     "author": {
       "familyName": null
     },
     "content": "Hang xinh gai sieu cap vjp pr0"
   }

Và kết quả nhận được cuối cùng là:

{
     "title": "From Hang xinh gai with love",
     "author" : {
       "givenName" : "Hang"
     },
     "tags":[ "girl_pho", "girl_thu_do" ],
     "content": "Hang xinh gai sieu cap vjp pr0"
   }

-- Nghe cũng đơn giản vl nhỉ?

-- Đơn giản mà. Thế ví dụ em muốn thay đổi tags thành "girl_ngoan_hien" và "1235_anh_co_danh_roi_nhip_nao_khong" thì làm thế nào?

-- Anh nghĩ chỉ cần gửi body lên với giá trị tag mới là xong?

PATCH /my/resource HTTP/1.1
   Host: example.org
   Content-Type: application/merge-patch+json
 
   {
     "tags":[ "girl_ngoan_hien", "1235_anh_co_danh_roi_nhip_nao_khong" ]
   }

-- That's right. Thế đố anh, ví dụ này thì sẽ nhận được gì? 

JSON gốc

{"a":"foo"}

Request body

PATCH /my/resource HTTP/1.1
   Host: example.org
   Content-Type: application/merge-patch+json

 null

-- ÁmụĐ, quả null khó thế

. Anh đoán là kết quả giữ nguyên {"a":"foo"}

-- Sai. Kết quả sẽ về null nhé.

-- Còn nhiều case đặc biệt không? Mày nói nốt cho anh biết nào?

-- Đầy đủ các case thì anh xem bảng sau

ORIGINAL        PATCH            RESULT
   ——————————————
   {"a":"b"}       {"a":"c"}       {"a":"c"}

   {"a":"b"}       {"b":"c"}       {"a":"b",
                                    "b":"c"}

   {"a":"b"}       {"a":null}      {}

   {"a":"b",       {"a":null}      {"b":"c"}
    "b":"c"}

   {"a":["b"]}     {"a":"c"}       {"a":"c"}

   {"a":"c"}       {"a":["b"]}     {"a":["b"]}

   {"a": {         {"a": {         {"a": {
     "b": "c"}       "b": "d",       "b": "d"
   }                 "c": null}      }
                   }               }

   {"a": [         {"a": [1]}      {"a": [1]}
     {"b":"c"}
    ]
   }

   ["a","b"]       ["c","d"]       ["c","d"]

   {"a":"b"}       ["c"]           ["c"]

   {"a":"foo"}     null            null

   {"a":"foo"}     "bar"           "bar"

   {"e":null}      {"a":1}         {"e":null,
                                    "a":1}

   [1,2]           {"a":"b",       {"a":"b"}
                    "c":null}

   {}              {"a":            {"a":
                    {"bb":           {"bb":
                     {"ccc":          {}}}
                      null}}}

-- Anh có thắc mắc gì nữa không? Em kết bài đây?

-- Hm... Anh đang nghĩ là mình có thể tự sáng tạo quy ước ra rồi code theo quy ước đấy là được nhỉ? Đỡ phải học nhiều chuẩn. Hơi...mệt.

-- Làm như anh mới là mệt. Anh đẻ ra một chuẩn mà không có nhiều người kiểm duyệt ~> rất dễ sai. Chưa kể anh tuyển người mới vào, họ lại phải đọc cái chuẩn của anh, làm learning curve tăng.

-- Ừ nhỉ. Thế đẹp nhất vẫn là lấy chuẩn quốc tế mà làm.

-- Chứ còn gì nữa..


Cảm ơn bạn, vì đã đọc bài.

Tranh thủ đầu xuân, trong lúc đọc code của một bạn đồng nghiệp thì mình nảy ra ý tưởng viết bài ~> vào việc luôn

Chúc bạn và gia đình một năm mới thật nhiều sức khỏe, đạt được các mục tiêu đặt ra trong 2024 nha ^^


Bài viết được lấy từ nguồn: Blog của mình