בונים Webhook שמקבל התראות - הפרויקט שמלמד אתכם אינטגרציה אמיתית¶
כל שירות חיצוני רציני - שירותי תשלום, מערכות קוד, שירותי הודעות - יודע להודיע לכם כשמשהו קורה אצלו, בלי שתצטרכו לשאול אותו כל הזמן. המנגנון נקרא webhook, וברגע שתבנו אחד בעצמכם, תבינו שהוא פשוט בעיקרון ומלא בפרטים קטנים שקל לפספס. הנה איך בונים נקודת קצה כזאת נכון, מהיסודות ועד לפרטים שמפילים אנשים.
Webhook מול polling - למה בכלל צריך את זה¶
הדרך הישנה לדעת אם קרה משהו היא polling - לשאול שוב ושוב "יש חדש?" כל כמה שניות. זה עובד, אבל מבזבז משאבים ותמיד יש עיכוב בין מה שקרה בפועל לבין הרגע שגיליתם. Webhook הופך את הכיוון - השירות החיצוני שולח לכם בקשת POST ביוזמתו, ברגע שקרה אירוע שהרשמתם אליו. אתם לא שואלים, אתם מקבלים הודעה. זה בדיוק מה שקורה כשמעבד תשלומים מודיע שעסקה הצליחה, או כשגיטהאב מודיע שמישהו פתח Pull Request חדש.
הפרויקט - נקודת קצה שמקבלת אירועים מגיטהאב¶
דוגמה טובה ללמידה היא endpoint שמקבל webhooks מגיטהאב - למשל, כל push לריפו שולח בקשה לכתובת שלכם, ואתם רוצים לתעד את זה או להפעיל בעקבותיו פעולה, כמו הרצת בדיקות. ה-route עצמו הוא הדבר הפשוט ביותר בפרויקט - בקשת POST רגילה עם גוף JSON. הקושי האמיתי הוא בכל מה שסביבו.
אימות חתימה - למה אסור לסמוך על כל בקשה¶
ה-endpoint שלכם הוא כתובת ציבורית. בלי הגנה, כל אחד יכול לשלוח אליה בקשה מזויפת שנראית כמו webhook אמיתי. הפתרון הוא חתימה דיגיטלית - השירות השולח (למשל גיטהאב) חותם כל בקשה עם מפתח סודי משותף, ומצרף את החתימה בכותרת הבקשה. התפקיד שלכם הוא לחשב את החתימה בעצמכם מגוף הבקשה, ולהשוות אותה לחתימה שהתקבלה:
const crypto = require("crypto");
function verifySignature(payload, signatureFromHeader, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureFromHeader)
);
}
אם החתימות לא תואמות, הבקשה נדחית מיד, לפני שהיא נוגעת בשום לוגיקה עסקית. דילוג על הבדיקה הזאת היא אחת הטעויות הנפוצות ביותר בפרויקטי webhook, ופותחת דלת לכל אחד להזרים אירועים מזויפים לתוך המערכת שלכם.
אידמפוטנטיות - כשאותו אירוע מגיע פעמיים¶
כמעט כל שירות שולח webhook שולח אותו שוב אם הוא לא קיבל אישור בזמן - גם אם העיבוד המקורי דווקא הצליח והתשובה פשוט לא הגיעה. המשמעות היא שה-endpoint שלכם חייב להיות אידמפוטנטי, כלומר לדעת להתמודד עם קבלה כפולה של אותו אירוע בלי לגרום לתקלה, כמו שליחת אימייל כפולה או עדכון כפול של רשומה. הדרך הפשוטה היא לשמור מזהה ייחודי לכל אירוע שכבר טופל, ולבדוק אותו לפני עיבוד חוזר.
תשובה מהירה, עיבוד ברקע¶
השירות השולח מצפה לתשובה תוך זמן קצר. אם ה-endpoint שלכם מבצע עיבוד כבד - שליחת מיילים, קריאה לשירותים נוספים - לפני שהוא עונה, השירות השולח עלול לחשוב שהבקשה נכשלה ולנסות שוב, למרות שהיא בעצם עדיין בעיבוד אצלכם. הפתרון הנכון הוא לאשר קבלה מיד עם קוד 200, לשמור את האירוע, ולהעביר את העיבוד הכבד לתור עבודה נפרד ברקע.
לוג שמאפשר לדבג בלי לנחש¶
webhooks נכשלים בשקט אם לא מתעדים אותם - בקשה שהגיעה עם חתימה שגויה, אירוע שנכשל בעיבוד, שליחה כפולה שזוהתה ונדחתה. לוג מסודר לכל אחד מהמקרים האלה חוסך שעות דיבוג כשמשהו לא עובד ואתם צריכים להבין אם הבעיה אצלכם או אצל השירות החיצוני.
איפה בונים את זה בפועל¶
לבנות endpoint שמקבל webhooks באמינות, כולל אימות חתימה, טיפול בכפילויות ולוג שמאפשר לדבג, זה משהו שנלמד הכי טוב תוך כדי אינטגרציה אמיתית עם שירות חיצוני. בקורס צד-שרת בונים בדיוק את זה בתוך פרויקט מקצה לקצה.
בונים אינטגרציה עם שירות חיצוני ונתקעתם עם webhook שלא מתנהג כמו שציפיתם? זה בדיוק סוג השאלה שכדאי לשאול בקהילה שלנו.