שינוי קטן ב-API יכול להפוך פיצ'ר שעובד היטב בבדיקות לתקלה אצל לקוח: אפליקציה שמפסיקה לקבל שדה, אינטגרציה שמפרשת ערך אחרת, או שירות AI שמחזיר תשובה ללא ציטוטים משום שחוזה התגובה השתנה. מדריך לניהול גרסאות API אינו עוסק רק במספר אחרי `/v1`. הוא עוסק בשמירה על חוזה ברור בין מערכות, בצמצום הפתעות וביכולת לשחרר שינוי בלי לנחש מי ייפגע.

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

מה באמת נשבר כשמשנים API

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

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

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

שינוי פנימי אינו בהכרח גרסה חדשה

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

גרסה חדשה נדרשת כאשר צרכן סביר של ה-API יצטרך לשנות קוד, הנחות או טיפול בשגיאות. הוספת שדה אופציונלי לתגובה בדרך כלל נחשבת שינוי תואם לאחור. אבל גם כאן יש הסתייגות: לקוחות עם schema קשיח, או frontend שמבצע השוואה מדויקת של אובייקטים, עלולים להיפגע. לכן לא מסתפקים בהגדרה תאורטית של "תאימות" - בודקים את הצרכנים בפועל.

בוחרים מדיניות לפני שבוחרים `/v2`

הטעות הנפוצה היא לפתוח גרסה חדשה בכל שינוי משמעותי, ואז להשאיר את `v1`, `v2`, `v3` ו-`v4` לתחזוקה ללא תאריך סיום, בדיקות מספקות או בעלות ברורה. זה מגדיל מהר מאוד את שטח התחזוקה ואת הסיכון לתיקוני אבטחה לא עקביים.

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

יש שלוש גישות מקובלות. אפשר לנהל גרסה בנתיב, למשל `/api/v1/orders`. זו גישה ברורה וקלה לצרכנים, ומתאימה במיוחד ל-API ציבורי או לאינטגרציות לקוחות. אפשר לנהל גרסה דרך header, כאשר הנתיב נשאר קבוע והלקוח מבקש media type או גרסה מסוימת. זו גישה נקייה יותר מבחינת URL, אך קשה יותר לאבחון ותיעוד. אפשר גם להימנע מגרסאות מפורשות ולבצע רק שינויים תואמים לאחור, תוך הוצאה מסודרת משימוש של יכולות ישנות.

לרוב מוצרי SaaS, אנחנו מעדיפים גרסת major גלויה בנתיב עבור שינויים שוברים, יחד עם משמעת שמונעת גרסאות מיותרות. היא מקלה על תמיכה, על ניטור ועל שיחה עם לקוח שמדווח על תקלה. אין כאן כלל מוחלט: אם ה-API פנימי לחלוטין וכל הצרכנים נפרסים יחד, ייתכן שגרסה בנתיב רק תוסיף רעש. אם יש SDKs, שותפים או לקוחות שמתחזקים אינטגרציה בעצמם, בהירות בדרך כלל חשובה יותר מאלגנטיות תיאורטית.

מדריך לניהול גרסאות API: תהליך שחרור בטוח

ניהול גרסאות טוב מתחיל לפני כתיבת הקוד. כאשר עולה בקשה לשינוי, קודם ממפים את החוזה הקיים ואת הצרכנים שלו. לא מספיק לחפש קריאות ל-endpoint בקוד הראשי. צריך לבדוק jobs, webhooks, שירותים פנימיים, אפליקציות מובייל, SDKs, סקריפטים תפעוליים ולקוחות חיצוניים.

מגדירים חוזה שניתן לבדוק

החוזה צריך להיות מפורש וקריא גם לאדם וגם למכונה. עבור כל endpoint כדאי להגדיר מבנה request ו-response, שדות חובה ואופציונליים, טיפוסים, קודי שגיאה, כללי pagination והרשאות. OpenAPI יכול לשמש לכך היטב, כל עוד הוא נשאר חלק מתהליך הפיתוח ולא מסמך שמתיישן אחרי השחרור.

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

מפרידים בין שינוי נוסף לשינוי שובר

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

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

מריצים בדיקות חוזה משני הצדדים

בדיקות unit בודקות את הלוגיקה בתוך שירות. הן לא מוכיחות שהלקוח עדיין מבין את התגובה. בדיקות חוזה בודקות שה-provider עומד במבנה ובהתנהגות שהוגדרו, ושצרכנים מרכזיים יודעים לעבוד מולו.

בפועל, כדאי לכלול ב-CI ולידציה של OpenAPI, בדיקות אינטגרציה על תגובות אמיתיות ובדיקות לצרכנים קריטיים. אם יש frontend ו-backend באותו ארגון, אפשר לבדוק את שניהם מול דוגמאות response קבועות. אם קיימים לקוחות חיצוניים, כדאי לשמור fixtures של תרחישים אמיתיים: הצלחה, הרשאה חסרה, נתונים חסרים, timeout ושגיאה עסקית.

ב-API שמגיש תשובות RAG, ה-evals צריכים לבדוק יותר מה-schema. eval הוא סט תרחישים וציפיות שמאפשר למדוד האם שינוי שמר על איכות התוצאה. למשל: האם תשובה עם מקור חסום אכן לא חושפת אותו, האם מקור מוצג רק כאשר הוא רלוונטי, והאם כשל retrieval מוחזר בפורמט שהלקוח יודע להציג. כך לא משחררים שינוי שמצליח טכנית אך פוגע בהתנהגות שהמשתמש רואה.

Deprecation הוא תהליך, לא הערה בתיעוד

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

כדאי להחזיר headers מתאימים, לרשום שימוש בגרסה הישנה, ולהציג לצוות תמונה של מי עדיין תלוי בה. אם יש לקוחות מזוהים לפי account או API key, אפשר לייצר רשימת צרכנים פעילים של הגרסה הישנה. הנתון הזה משנה את השיחה: במקום להניח שאפשר לכבות `v1`, יודעים אילו אינטגרציות דורשות תיאום.

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

הרשאות, observability ועלות בכל גרסה

גרסה חדשה אינה פטורה מכללי האבטחה של הישנה. זו נקודת כשל נפוצה: `v2` נבנית מהר, ובדרך נשכחת בדיקת tenant, סינון מסמכים לפי הרשאה או audit log שהיה קיים בנתיב המקורי. כל גרסה צריכה לעבור בדיקות הרשאה מפורשות, כולל ניסיונות גישה לנתונים של account אחר.

צריך גם למדוד כל גרסה בנפרד: שיעור שגיאות, זמני תגובה, שימוש לפי endpoint, עלויות של קריאות לספקים חיצוניים ותוצאות עסקיות רלוונטיות. ללא observability - יכולת להבין מה המערכת עושה דרך לוגים, metrics ו-traces - קשה לדעת אם ההגירה הצליחה או אם לקוחות פשוט עוקפים את הנתיב החדש.

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

מתי לעצור ולבדוק את הארכיטקטורה

אם כל שינוי קטן מחייב `v3`, `v4` או תנאי מיוחד לעשרה לקוחות, ייתכן שהבעיה אינה רק מדיניות גרסאות. לעתים החוזה מערבב כמה אחריויות: נתוני ליבה, הרשאות, תצוגה ותוצאת AI באותה תגובה. במקרים כאלה כדאי להפריד endpoints או להגדיר מודלים ברורים יותר, במקום להעמיס שכבות תאימות על API שכבר קשה להבין.

אנחנו ב-DevCo Solutions בודקים ניהול גרסאות כחלק מאמינות המערכת כולה: חוזי API, הרשאות, retrieval, ציטוטים, evals ותהליך release. אם יש לכם API חי ששינויים בו מרגישים מסוכנים, התחילו ממיפוי של הצרכנים והחוזים הפעילים. לאחר מכן אפשר לקבוע תהליך קטן, ברור וניתן לאכיפה. לשיחה קצרה על מצב המערכת שלכם, השאירו פרטים דרך טופס יצירת הקשר באתר.