1. ספרייה
  2. HTTP והרשת
  3. שיטות HTTP

עודכן לפני חודש

כל מפתח שואל בסופו של דבר את אותה שאלה: אם אני שולח עדכון מבלי לכלול כל שדה, מה קורה לשדות שהשמטתי?

התשובה תלויה לגמרי בשאלה אם אתה משתמש ב-PUT או ב-PATCH.

PUT אומר "זוהי האמת השלמה עכשיו." כל מה שאתה שולח מחליף את מה שקיים. שדות שהשמטת נמחקים — או מאופסים לערכי ברירת המחדל. אתה לא מעדכן; אתה מחליף לחלוטין.

PATCH אומר "שנה את הדברים האלה, השאר את השאר." רק השדות שכללת משתנים. כל השאר נשאר בדיוק כפי שהיה.

ההבחנה הזו נשמעת פשוטה, אבל היא קובעת כיצד אתה בונה בקשות, כיצד שרתים מעבדים אותן, ואם שדה שנשכח עלול לגרום לתקלה בסביבת הייצור.

PUT: החלפה מלאה

PUT שולח את כל ייצוג המשאב. השרת לא ממזג — הוא מחליף.

נניח שיש לך פרופיל משתמש:

{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "bio": "Software developer",
  "location": "New York"
}

כדי לעדכן את כתובת הדוא"ל עם PUT:

PUT /users/123 HTTP/1.1
Content-Type: application/json

{
  "id": 123,
  "name": "John Doe",
  "email": "john.doe@example.com",
  "bio": "Software developer",
  "location": "New York"
}

עליך לכלול הכל — אפילו את השדות שלא השתנו. אם שלחת רק:

{
  "id": 123,
  "email": "john.doe@example.com"
}

השדות name, bio ו-location היו נמחקים. זה לא באג. זהו החוזה הסמנטי של PUT: מה שאתה שולח הוא המצב החדש המלא.

PATCH: עדכון ממוקד

PATCH שולח רק את מה שצריך להשתנות:

PATCH /users/123 HTTP/1.1
Content-Type: application/json

{
  "email": "john.doe@example.com"
}

השרת משנה את כתובת הדוא"ל ומשאיר את כל השאר ללא שינוי. התוצאה:

{
  "id": 123,
  "name": "John Doe",
  "email": "john.doe@example.com",
  "bio": "Software developer",
  "location": "New York"
}

PATCH מביע את הכוונה בצורה מדויקת יותר: "שנה את הדבר הספציפי הזה." הבקשה קטנה יותר, ואין סיכון שתמחק בטעות שדות שרצית לשמור.

שאלת האידמפוטנטיות

PUT הוא תמיד אידמפוטנטי. שלח את אותה בקשת PUT עשר פעמים ותקבל את אותה תוצאה — המשאב יגיע בדיוק למצב שציינת. זה הופך את PUT לבטוח לניסיון חוזר אם בקשת רשת נכשלת.

PATCH מסובך יותר. הגדרת שדה לערך ספציפי היא אידמפוטנטית:

{"email": "new@example.com"}

החל את זה מאה פעמים; כתובת הדוא"ל עדיין תהיה new@example.com.

אבל שינויים יחסיים אינם אידמפוטנטיים:

{"balance": {"increment": 10}}

החל את זה פעמיים והוספת 20, לא 10. האם PATCH הוא אידמפוטנטי תלוי במה שאתה מעדכן ובאיזו שיטה.

מתי להשתמש בכל אחד

השתמש ב-PUT כאשר:

  • ממילא אתה מחליף את כל המשאב
  • הלקוח טען את המצב הנוכחי המלא ושולח חזרה שינויים
  • אתה זקוק לאידמפוטנטיות מובטחת
  • אובייקטי תצורה שבהם מצב חלקי אינו הגיוני

השתמש ב-PATCH כאשר:

  • לקוחות בדרך כלל משנים שדה אחד או שניים בכל פעם
  • המשאב גדול ושליחתו כולה מבזבזת רוחב פס
  • לקוחות מרובים עשויים לעדכן שדות שונים בו-זמנית
  • אתה רוצה שהבקשה תבטא בדיוק מה משתנה

פורמטי PATCH

בניגוד ל-PUT, שמשתמש בייצוג הסטנדרטי של המשאב, PATCH יכול לתאר שינויים בדרכים שונות.

JSON Merge Patch (RFC 7396) הוא הפשוט ביותר: שלח אובייקט עם השדות שאתה רוצה לעדכן. הגדר שדה ל-null כדי למחוק אותו. השמט שדות כדי להשאירם ללא שינוי.

{
  "email": "new@example.com",
  "bio": null
}

זה מעדכן את כתובת הדוא"ל ומסיר את הביוגרפיה. פשוט, אבל אינו יכול להבחין בין "הגדר שדה זה ל-null" לבין "מחק שדה זה" — שניהם משתמשים ב-null.

JSON Patch (RFC 6902) משתמש במערך של פעולות מפורשות:

[
  {"op": "replace", "path": "/email", "value": "new@example.com"},
  {"op": "remove", "path": "/bio"},
  {"op": "add", "path": "/tags/-", "value": "verified"}
]

חזק יותר — ניתן להוסיף למערכים, להעביר ערכים, ואפילו לבדוק תנאים לפני החלת שינויים — אבל מורכב יותר לממש.

רוב ה-API-ים משתמשים ב-JSON Merge Patch בגלל פשטותו. בחר ב-JSON Patch כאשר אתה זקוק לשליטה מדויקת על מערכים או עדכונים מותנים.

טיפול בשינויים בו-זמניים

PATCH יוצר סיכון של מצב תחרות. שני לקוחות קוראים את אותו משאב, שניהם שולחים עדכונים, והשני מחליף את שינויי הראשון מבלי לדעת שהם קיימים.

הפתרון הוא נעילה אופטימיסטית עם ETags:

PATCH /users/123 HTTP/1.1
If-Match: "abc123"
Content-Type: application/json

{"email": "new@example.com"}

השרת מחיל את העדכון רק אם ה-ETag של המשאב עדיין תואם. אם מישהו אחר שינה אותו קודם, תקבל 412 Precondition Failed ותוכל לטעון מחדש, למזג ולנסות שוב.

ל-PUT יש את אותה בעיה, אבל לעתים קרובות היא פחות בעייתית מכיוון שאתה שולח את המצב המלא. אפשר שתחליף שינויים של מישהו אחר, אבל לפחות לא תשאיר את המשאב במצב חלקי בלתי צפוי.

יצירת משאבים

PUT יכול ליצור משאבים בכתובות URL שציין הלקוח:

PUT /users/johndoe HTTP/1.1

{"name": "John Doe", "email": "john@example.com"}

אם /users/johndoe אינו קיים, הוא נוצר. אם הוא קיים, הוא מוחלף. יצירה אידמפוטנטית זו שימושית כאשר לקוחות יכולים ליצור מזהים משמעותיים — שמות משתמש, מק"טים, UUIDs.

PATCH בדרך כלל רק משנה משאבים קיימים. ניסיון לבצע PATCH על משאב שאינו קיים מחזיר 404.

קודי תגובה

גם PUT וגם PATCH מחזירים בדרך כלל:

  • 200 OK: הצלחה, התגובה כוללת את המשאב המעודכן
  • 204 No Content: הצלחה, אין גוף תגובה (הלקוח מסיק את המצב החדש)
  • 400 Bad Request: בקשה שגויה
  • 404 Not Found: המשאב אינו קיים
  • 409 Conflict: העדכון מתנגש עם המצב הנוכחי
  • 412 Precondition Failed: אי-התאמה של ETag

PUT עשוי גם להחזיר 201 Created בעת יצירת משאב חדש.

החזרת המשאב המעודכן בתגובה חוסכת בקשת GET נוספת. החזרת 204 חוסכת רוחב פס. שתי הגישות עובדות; רק שמור על עקביות.

שאלות נפוצות על PUT מול PATCH

מה קורה אם אני משתמש ב-PUT אבל שוכח לכלול שדה?

השדה נמחק או מאופס לערך ברירת המחדל שלו. PUT פירושו החלפה — אם השדה אינו בבקשה שלך, הוא לא יהיה במשאב לאחר מכן. זוהי הטעות הנפוצה ביותר כאשר מפתחים משתמשים ב-PUT לעדכונים חלקיים.

האם PATCH יכול ליצור משאב חדש כמו PUT?

בדרך כלל לא. PATCH מיועד לשינוי משאבים קיימים. רוב ה-API-ים מחזירים 404 אם אתה מנסה לבצע PATCH על משאב שאינו קיים. השתמש ב-PUT או ב-POST ליצירה.

איזה מהם צריך ה-API שלי לתמוך?

שניהם. PUT ללקוחות שרוצים להחליף משאבים שלמים, PATCH ללקוחות שרוצים עדכונים ממוקדים. אם אתה יכול לבחור רק אחד, PATCH הוא בדרך כלל המעשי יותר — עדכונים חלקיים הם המקרה הנפוץ.

האם PATCH יעיל תמיד יותר מ-PUT?

עבור משאבים גדולים עם שינויים קטנים, כן. עבור משאבים קטנים או כאשר מעדכנים רוב השדות, ההבדל זניח. JSON Patch יכול להיות למעשה מפורט יותר מאשר פשוט לשלוח את כל המשאב כאשר השינויים מורכבים.

האם דף זה היה מועיל?

😔
🤨
😃
PUT מול PATCH • ספרייה • Connected