עודכן לפני חודש
REST אינו קובץ חוקים לשינון. זוהי הימור: אם תארגן את ה-API שלך סביב משאבים ותשתמש ב-HTTP כפי שהוא תוכנן, מפתחים יוכלו לנחש כיצד ה-API שלך עובד לפני שיקראו את התיעוד שלך.
ההימור הזה משתלם כל הזמן. מפתח שמעולם לא ראה את ה-API שלך יכול לנחש ש-GET /users/123 מאחזר משתמש, ש-DELETE /users/123 מסיר אותו, ו-POST /users יוצר משתמש חדש. הוא לא קרא את התיעוד שלך. הוא פשוט ידע.
זהו הפרס. כל השאר — מוסכמות השמות, קודי הסטטוס, פורמטי התגובה — קיים כדי להגן על צפיות זו.
משאבים, לא פרוצדורות
השינוי המהותי ב-REST הוא לחשוב על מה שהדברים הם, לא על מה שאפשר לעשות להם.
חשיבה פרוצדורלית מייצרת נקודות קצה כמו /getAllUsers, /createNewOrder, /updateUserEmail. חשיבה מוכוונת-משאבים מייצרת /users, /orders, /users/123. שיטת ה-HTTP נושאת את הפועל; ה-URI מזהה את השם.
זה לא רק אסתטיקה. כאשר כל נקודת קצה היא פרוצדורה מותאמת אישית, מפתחים חייבים ללמוד כל אחת בנפרד. כאשר נקודות הקצה הן משאבים, מפתחים לומדים את התבנית פעם אחת ומיישמים אותה בכל מקום.
מצא את השמות בתחום שלך. משתמשים, הזמנות, מוצרים, תגובות, תשלומים — אלה הם המשאבים שלך. אם אתה מתקשה לתת שם למשהו כשם עצם, ייתכן שאתה מנסה לחשוף פרוצדורה שצריכה להיות מטופלת אחרת.
היררכיות בעלות משמעות
למשאבים יש קשרים. למשתמש יש הזמנות. להזמנה יש פריטים. לפוסט יש תגובות.
בטא אותם דרך קינון: /users/123/orders מחזיר הזמנות השייכות למשתמש 123. /posts/456/comments מחזיר תגובות על פוסט 456. ה-URI עצמו מבטא את הקשר.
אבל שים לב לסימן אזהרה: אם אתה בונה URIs כמו /users/123/orders/456/items/789/modifiers/012, עצור. קינון עמוק אינו רק מכוער — הוא מסמן שמשהו לא בסדר במודל שלך. בדרך כלל זה אומר שמשאבים שצריכים להיות נגישים ישירות נאלצים לעבור דרך הורים מיותרים.
שאל את עצמך: האם מישהו צריך /items/789 ישירות? אם כן, הפוך אותו נגיש ב-/items/789. ההיררכיה ב-/orders/456/items יכולה להתקיים יחד עם גישה ישירה.
URIs כהבטחות
URI מעוצב היטב הוא הבטחה לגבי מה תמצא שם.
שמות עצם ברבים לאוספים. /users הוא אוסף, /users/123 הוא משתמש אחד. עקביות זו אומרת שמפתחים לא יתלבטו אם להשתמש ב-/user או ב-/users.
אותיות קטנות עם מקפים. /user-profiles קריא יותר מ-/UserProfiles או /user_profiles. חשוב מכך, זה מונע בלבול רגישות לרישיות — מערכות מסוימות מתייחסות ל-/Users ו-/users כמסלולים שונים.
ללא דליפת פרטי מימוש. /users.php, /api/rest/users.json, /v1/userController/getAll — אלה חושפים פרטי מימוש שלא צריכים לעניין את הלקוחות. כשאתה עובר מ-PHP ל-Node, ה-URIs שלך לא צריכים להשתנות.
קצר וניתן לניחוש. אם מפתח לא יכול לנחש את ה-URI של משהו, השמות שלך נכשלו. /api/v1/customers/123/orders עובד. /api/v1/customer-management-system/customer-resource/123/order-processing-module/order-collection לא עובד.
שיטות HTTP יש להן משמעות
שיטות HTTP אינן תוויות שרירותיות. יש להן סמנטיקה, והפרת אותה שוברת את ההימור.
GET הוא קדוש. GET לעולם לא צריך לשנות שום דבר. ללא תופעות לוואי, ללא שינויי מצב, כלום. סורק שמגיע לנקודות הקצה GET שלך לא צריך למחוק נתונים או לשלוח מיילים. אם GET /users/123 לפעמים יוצר משתמש, שברת את הרשת.
POST יוצר. POST /users יוצר משתמש. השרת מקצה את המזהה ומחזיר אותו. POST הוא השיטה היחידה שאינה אידמפוטנטית — קריאה אליה פעמיים יוצרת שני משאבים.
PUT מחליף. PUT /users/123 מחליף את המשתמש כולו. אם אתה שולח רק {"name": "John"}, שדות אחרים צריכים להימחק. PUT הוא אידמפוטנטי — שליחת אותו PUT שוב ושוב מייצרת את אותה תוצאה.
PATCH משנה. PATCH /users/123 עם {"email": "new@example.com"} משנה רק את כתובת האימייל. שדות אחרים נשארים ללא שינוי. השתמש ב-PATCH כאשר אתה רוצה עדכונים מדויקים.
DELETE מסיר. DELETE /users/123 מסיר את המשתמש. DELETE הוא אידמפוטנטי — מחיקת משהו שכבר נמחק אינה שגיאה, היא פעולה שלא עושה כלום.
כאשר אתה משתמש בשיטות אלה בצורה נכונה, לקוחות יכולים לעשות הנחות. הם יודעים ש-GET בטוח לניסיון חוזר. הם יודעים ש-PUT ו-DELETE בטוחים לניסיון חוזר אם הרשת נכשלת. הם יודעים ש-POST עלול לא להיות. הנחות אלה מאפשרות להם לבנות אינטגרציות חזקות יותר מבלי לקרוא את התיעוד שלך.
תגובות שמלמדות
כל תגובה היא הזדמנות לעזור ללקוח.
החזר את מה שיצרת. כאשר POST יוצר משאב, החזר אותו. הלקוח שלח לך נתונים חלקיים; הוספת מזהה, חותמות זמן וערכי ברירת מחדל. תן לו בחזרה את התמונה המלאה. כלול כותרת Location המצביעה על המשאב החדש.
החזר את מה ששינית. כאשר PUT או PATCH מעדכנים משהו, החזר את המשאב המעודכן. לוגיקה בצד השרת עשויה לשנות שדות אחרים, לנרמל נתונים, או לעדכן חותמות זמן. אל תגרום ללקוחות לנחש.
היה עקבי. אם /users/123 מחזיר {"id": "123", "name": "John", "email": "..."}, אז כל נקודת קצה של משתמש צריכה להחזיר את המבנה הזה. חוסר עקביות מאלץ לקוחות לטפל במקרים מיוחדים.
אוספים צריכים הקשר. רשימה של 50 משתמשים חסרת ערך מבלי לדעת שיש 1,500 בסך הכל. כלול מטא-נתוני עימוד:
שגיאות שעוזרות
טיפול רע בשגיאות הוא המקום שבו APIs מאבדים את אמון המפתחים.
קודי סטטוס אינם אופציונליים. החזרת 200 OK עם {"success": false, "error": "..."} שוברת HTTP. לקוחות בודקים קודי סטטוס תחילה. השתמש ב-4xx לשגיאות לקוח, ב-5xx לכשלי שרת.
אמור מה השתבש. "בקשה לא חוקית" לא עוזרת לאף אחד. "פורמט כתובת האימייל אינו חוקי" עוזרת. "האימייל חייב להכיל את הסימן @" עוזרת עוד יותר.
ספק קודי שגיאה יציבים. הודעות בשפה טבעית משתנות. קודי שגיאה לא. INVALID_EMAIL_FORMAT מאפשר ללקוחות לטפל בשגיאות ספציפיות בצורה תכנותית מבלי לנתח משפטים באנגלית.
החזר את כל שגיאות האימות בבת אחת. אם האימייל לא חוקי וגם הגיל נמוך מדי, אמור את שניהם. לגרום למפתחים לתקן שגיאה אחת, לשלוח שוב, לגלות שגיאה נוספת, לשלוח שוב — זה עוין.
לעולם אל תחשוף את הפנים. מעקבי מחסנית, שגיאות SQL, נתיבי קבצים — אלה עוזרים לתוקפים ומבלבלים מפתחים. רשום אותם בצד השרת; החזר ללקוחות משהו כללי בלבד.
עימוד: בחר את הפשרה שלך
אי אפשר להחזיר 100,000 משתמשים בתגובה אחת. עימוד הוא הכרחי. השאלה היא איזה סוג.
עימוד לפי היסט הוא אינטואיטיבי: ?page=2&per_page=50 או ?offset=100&limit=50. מפתחים מבינים אותו מיד. אבל יש בו פגם: אם פריטים נוספו או נמחקו בין בקשות דפים, תראה כפילויות או תחמיץ פריטים. לנתונים המשתנים לאט, זה לרוב לא משנה. לזרמים בזמן אמת, זוהי בעיה.
עימוד לפי סמן משתמש בסמן אטום: ?cursor=abc123&limit=50. התגובה כוללת את הסמן הבא. זה מטפל נכון בקבוצות נתונים משתנות — לעולם לא תחמיץ פריטים ולא תראה כפילויות. אבל אי אפשר לקפוץ לדף 47. אפשר רק לנוע קדימה (או אחורה עם סמן קודם).
אף אחד אינו עדיף תמיד. עימוד לפי היסט עובד עבור לוחות ניהול שבהם המשתמשים קופצים בין דפים. סמנים מתאימים לזרמים עם גלילה אינסופית שבהם תמיד נעים קדימה.
מה שלא תבחר, קבע מגבלת ברירת מחדל. GET /users ללא הגבלה שמחזיר 500,000 רשומות יפיל את השרת שלך ואת הלקוח.
סינון ללא ריבוי נקודות קצה
ללא סינון, בסופו של דבר תגיע לנקודות קצה כמו /active-users, /admin-users, /users-created-this-week. זה לא ניתן להרחבה.
פרמטרי שאילתה ניתנים להרחבה:
מיון עובד באותו אופן:
בחירת שדות מפחיתה את גודל המטען:
התבנית עקבית: ה-URI מזהה את המשאב, פרמטרי השאילתה מגדירים כיצד אתה רוצה לקבל אותו.
גרסאות: תכנן לשינויים
APIs מתפתחים. לקוחות שתלויים בהתנהגות הישנה לא צריכים להישבר כשאתה משיק את הגרסה החדשה.
גרסאות URI הן מפורשות: /v1/users ו-/v2/users יכולים להתקיים במקביל. מפתחים רואים את הגרסה בכל בקשה. החיסרון הוא הצטברות גרסאות בסימניות, בתיעוד ובקוד הלקוח.
גרסאות כותרת שומרות על URIs נקיים: Accept: application/vnd.api.v2+json. החיסרון הוא חוסר נראות — אי אפשר לדעת את הגרסה מה-URL בלבד.
רוב הצוותים בוחרים בגרסאות URI לפשטותן. מה שלא תבחר, צריכה להיות לך מדיניות הוצאה משימוש. הכרז על תאריכי סיום תמיכה. כלול אזהרות הוצאה משימוש בתגובות. תן ללקוחות זמן לעבור לגרסה החדשה.
אבטחה אינה אופציונלית
HTTPS בכל מקום. לא רק לכניסה לחשבון — לכל דבר. מפתחות API, אסימונים ונתונים חייבים להיות מוצפנים בדרכם. אין תירוץ ל-HTTP פשוט בשנת 2024.
אמת הכל. נתוני הלקוח הם עוינים עד שהוכחה אחרת. בדוק סוגים, אורכים, פורמטים וטווחים. דחה קלט לא חוקי עם שגיאות ברורות.
זהה את המשתמשים. דע מי קורא. מפתחות API, אסימוני OAuth, JWTs — בחר פתרון מתאים לשימוש שלך.
הרשאות. זיהוי אומר לך מי; הרשאות אומרות לך מה מותר להם לעשות. משתמש 123 יכול לקרוא את ההזמנות שלו אך לא את אלה של משתמש 456.
הגבל קצב. ללא מגבלות, לקוח אחד שמתנהג בצורה גרועה יכול להפיל את השירות שלך לכולם. החזר 429 Too Many Requests עם כותרת Retry-After.
ההימור מנוסח מחדש
REST הוא הימור על צפיות. כל עיקרון כאן — משאבים על פני פרוצדורות, שיטות HTTP נכונות, תגובות עקביות, שגיאות מועילות — משרת את ההימור הזה.
כשאתה מנצח, מפתחים משתלבים עם ה-API שלך בשעות במקום ימים. הם מנחשים נכון במקום לחפש בתיעוד. הם סומכים על ה-API שלך כי הוא מתנהג כפי שמצפים ממנו.
כשאתה מפר עקרונות אלה, אתה לא רק שובר מוסכמות. אתה שובר את ההנחות שמאפשרות למפתחים לעבוד ביעילות. כל חריג הוא מקרה מיוחד שהם חייבים ללמוד ולזכור.
הכללים אינם שרירותיים. הם החוכמה הצבורה של מה שהופך APIs לצפויים. עקוב אחריהם, ותירש את הצפיות הזו בחינם.
שאלות נפוצות על עיצוב RESTful
מתי כדאי להשתמש ב-PUT לעומת PATCH?
השתמש ב-PUT כשאתה מחליף את המשאב כולו — שולח ייצוג מלא שצריך לדרוס את מה שקיים. השתמש ב-PATCH כשאתה משנה שדות ספציפיים תוך השארת האחרים ללא שינוי. אם הלקוחות שלך בדרך כלל מעדכנים שדה אחד בכל פעם, PATCH ידידותי יותר. אם הם תמיד שולחים אובייקטים שלמים, PUT ברור יותר.
כיצד אני מטפל בפעולות שאינן מתאימות לפעולות CRUD?
פעולות מסוימות — ביטול הזמנה, העברת פוסט לארכיון, שליחה מחדש של הזמנה — מרגישות כמו פעלים, לא שמות עצם. שתי גישות עובדות: מדל את הפעולה כתת-משאב (POST /orders/123/cancellation) או כשינוי מצב (PATCH /orders/123 עם {"status": "cancelled"}). גישת תת-המשאב ברורה יותר כאשר לפעולה יש נתונים או היסטוריה משלה.
האם כדאי להשתמש ב-UUIDs או במזהים רציפים?
מזהים רציפים פשוטים וקצרים יותר, אבל הם דולפים מידע (מתחרים יכולים להעריך את מספר המשתמשים שלך) ויוצרים צווארי בקבוק בבסיסי נתונים מבוזרים. UUIDs אטומים וידידותיים לסביבות מבוזרות, אבל ארוכים יותר וקשים לתקשר בעל פה. צוותים רבים משתמשים ב-UUIDs חיצונית תוך שמירה על מזהים רציפים פנימית.
כיצד להבחין בין שינויים שוברים לשינויים שאינם שוברים?
הוספת שדות חדשים, נקודות קצה חדשות או פרמטרים אופציונליים חדשים אינה שוברת — לקוחות קיימים מתעלמים ממה שאינם מבינים. הסרת שדות, שינוי סוגי שדות, או שינוי התנהגות הם שבירה ודורשים עלייה בגרסה. המבחן: האם קוד הלקוח הקיים עדיין יעבוד ללא שינויים?
האם דף זה היה מועיל?