2016-10-04

REST ו RESTful APIs - גרסת 2016

איי שם בשנת 2011 כתבתי פוסט על REST ו RESTful APIs. פוסט שנצפה דיי הרבה פעמים, וגם עורר שאלות ותגובות. לפני כשבוע שאל אותי עוד מישהו על אחת הדוגמאות שנתתי. דוגמה כיצד לא-לכתוב REST Endpoint.

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

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

הניסיונות למסד את רעיונות ה REST שהזכרתי בפוסט המקורי - פרוטוקולי GData ו OData (של גוגל ומייקרוסופט, בהתאמה) - לא ממש תפסו. לניסיון הנוכחי, שזוכה לתשומת לב בימים אלו, JSON API - אני מעריך שיהיה גורל דומה: השפעה מוגבלת באזורים מסוימים בתעשייה. רעיון יפה שיהיו כאלו שישתמשו בו בהצלחה - אך הוא לא יסחוף את כלל התעשייה כמו REST.

רעיונות ה REST באמת גרמו לסחף אדיר בתעשיה, ושינו בתוך שנים ספורות את האופן בו אנו מגדירים APIs בין מערכות / תתי-מערכות.

מה כ"כ חזק ברעיונות ה REST שגרם לשינוי האדיר הזה?
מדוע פרוטוקולים "נבונים" יותר ו"מעודכנים" יותר, כמו GData, OData, או JSON API - לא זוכים לכזו תהודה?
מה סוד הקסם של REST?

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

כלומר: אפשר לומר שמרבית התעשייה עובדת עם "פסדו-REST", ורק חלקים קטנים יותר עובדים עם "REST תקני" או אפילו "REST תקני חלקית".
אם נשווה את מספר המשתמשים ב "REST תקני (חלקית)" - סדרי הגודל של המשתמשים דומים כנראה למספרי השמתמשים בפרוטוקולים חלופיים, קרי JSON API, OData, GData, או Thrift (שפותח במקור ע"י פייסבוק).

בעוד הפוסט המקורי מ-2011 נועד להוות "קריאת השכמה" ולהראות כיצד ליישם "REST תקני"... בפוסט הזה אני אנקוט גישה מעט שונה. בכל זאת, מתבגרים... :)




מה הרעיון ב REST?


הרעיון, ביישום המקובל שלו, הוא שבמקום ש"נמציא" פרוטוקול תקשורת חדש לווב, נשתמש בפרוטוקול של הווב - הרי הוא פרוטוקול ה HTTP. פרוטוקול אמין, מוכר, ומוכח ב Scales אדירים.

בגישה זו, יש מספר לא מבוטל של יתרונות:
  • ל HTTP יש המון ספריות, לכל שפת תכנות בערך, והרבה אנשים מכירים אותו לעומק. (אם אתם לא מכירים - זה זמן טוב לקורא את הפוסט בנושא!)
  • אם נפעל בהתאם ל HTTP, נוכל להינות בהשקעה קטנה מצידנו מ Caching שרכיבי הרשת השונים כבר מספקים (Proxies, gateways, CDNs, וכו').
  • רכיבי אבטחת רשת מקובלים (IDS או WAF) מכירים HTTP. הנה לנו פרוטוקול שכבר יש לו תמיכה בלא-מעט כלי אבטחה.
  • HTTP הוא פשוט ויעיל. מתחת למכסה המנוע הוא פשוט כמה headers שנשלחים לפני ההודעה על גבי חיבור ה TCP.
  • HTTP הוא stateless (ברובו הגדול), וה Scalability שלו היא מוכחת! (ה world wide web, דאא)
  • HTTP קל לניטור והבנה (יש הרבה כלים + הוא מבוסס clear text).


ע"פ ההגדרות הפורמאליות, REST אינו בהכרח קשור ל HTTP. הוא מבסס עקרונות (או Constraints) של ה API של המערכת, שדומים מאוד לאלו של רשת האינטרנט:
  • תקשורת שרת-לקוח
  • ה API הוא Stateless
  • ניתן לבצע Cache לבקשות
  • ממשק אחיד, לכלל המערכת:
    • מבוסס מיפוי של משאבים (כלל מנחה: שמם מורכב משמות-עצם)
    • על כל המשאבים ניתן לבצע סט מוגדר של פעולות: קריאה, כתיבה, עדכון, וכו'. (דומה מאוד ל HTTP GET, HTTP POST, וכו').
    • ה API מתאר את עצמו - ולקוח ה API משתמש בתיאור זה בצורה "גנרית" על מנת להשתמש ב API.

כיצד הסתירה הזו מתיישבת? נסביר בהמשך.







היסטוריה: כיצד נולד ה REST?


רעיונות ה REST הופיעו בפעם הראשונה בעבודת הדוקטורט של Roy T. Fielding, חבר בצוות שהגדיר את פרוטוקול ה HTTP וכן co-author של ה Apache Web Server.

עבודת הדוקטורט של פידלינג עסקה באפיון של רעיון שנקרא "סגנונות ארכיטקטוניים", מן דפוסים מרכזיים וחוזרים בארכיטקטורות של תוכנות שונות. בפרק מספר 5 בעבודה הוא תיאר סגנון ארכיטקטוני בשם (Representational State Transfer (REST - אימוץ העקרונות מאחורי ה world wide web, על מנת לתקשר בין שרתים.

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

כמה שנים לאחר מכן, ב 2003 עד 2005 בערך - העולם נכנס לסערה של Service Oriented Architecture (בקיצור: SOA) והרעיון של Web Services (רשימת תקנים בשם *-WS).
אפשר להשוות את ההשפעה של SOA לאופנה הנוכחית של Microservices. לי, כמפתח צעיר, הרעיונות נשמעו מלהיבים וגדולים - ובחברה שעבדתי בה באותה התקופה החליטו "לא לפגר מאחור - ולאמץ SOA עד הסוף". כמובן שלי ולחברי לא היה מושג בדיוק כיצד להוציא מ SOA את המיטב - ופשוט מימשנו SOA ו Web Services.

Web-Services היו הפשטה גבוהה ועשירה/מסובכת מעל הפרימיטיביים של הווב. היה שם XMLs גדולים ומורכבים, שנעטפו בתוך XML נוסף (ה envelope) שהיה חלק מפרוטוקול התקשורת - SOAP, ותוארו ע"י פורמט שנקרא WSDL והופץ על גבי פרוטוקול בשם UDDI ואז היה ניתן להשתמש בכלי בשם DISCO על מנת למצוא אותם. וזה היה רק הבסיס.

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

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

ב 2004 ה W3C (ארגון התקינה של האינטרנט) הוציא מסמך שדן בארכיטקטורות אינטרנט. לקראת סוף המסמך, הופיעה פסקה קצרה המרחיבה את ההגדרה של Web Services: היא גם ציינה את REST כבסיס התיאורטי לפעולת ה Web Services, וגם ציין שהם יכולים להיות בלתי-תלויים בפרוטוקולים כמו WSDL או SOAP.

יריית הפתיחה נורתה, ושני מחנות החלו להיווצר:
  • אלו התומכים ב Web Services ע"פ סט תקני ה *-WS.
  • אלו התמוכים ב RESTful Web Services, כלומר: עלינו רק לתאום לכללי ה REST - וזהו Web Service בר-תוקף, בהכשרת ה W3C!
על עצם הצורך בהגדרה של Web Services, או של SOA - אף אחד לא ערער. זה היה באזז חזק שלא ניתן להתכחש לו.
היום כמעט כבר אין ממש זכר ל *-WS, ומעט מאוד מ SOA. הקונצנזוס הגדול התעשייה הוא סביב REST - כאשר עדיין יש הרבה חוסר הבנה מסביב לעקרונות הללו.


קצת עזרה מידידנו ריצארדסון


את חוסר ההבנה ב REST, ניסה קצת להבהיר / לסדר בחור בשם לאונרד ריצרדסון.

ריצרדסון הוא המחבר של שני ספרים מוכרים (הוצאת O'Reilly):
  • RESTful Web Services - 2007
  • RESTful Web APIs - 2013
בהרצאה בכנס QCON-2008, ריצרדסון הציג מודל בגרות של אימוץ רעיונות ה REST:

מקור: http://www.slideshare.net/josdirksen/rest-from-get-to-hateoas


רמה 0 - הביצה של POX (קיצור של Plain Old XML. פורמט ה XML היה בזמנו יותר פופולרי מ JSON)

רמה זו מתארת שימוש ב HTTP בכדי להעביר קבצי JSON או XML, נניח תמיד במתודת HTTP POST. זה יישום פשוט, Freestyle (שזה סוד הקסם שלו) - אך זה לא REST.

זה כמובן לא מפריע לקרוא לו REST - ויש אנשים שבאמת מתייחסים לכל פורמט סטנדרטי (נניח JSON) שעובר ל HTTP - כ REST. לא נבוא איתם בחשבון :-)



רמה 1 - מיפוי משאבים

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

בעוד שיכולנו לתאר API של מערכת לניהול כנסים כ:

  • POST /create_session
  • POST /set-session-title
מיפוי של משאבים יתייחס לקריאות הללו בצורה בה מתייחסים למשאבים:
  • POST /sessions/create
  • POST /sessions/<session_id>/title

מכיוון שה title שייך ל session, אנו מרכיבים את ה URI בצורה היררכית - כך ש session קודם (ולכן "מכיל") את ה title. כלומר: כל "/" מתאר בהכרח רמה היררכית של מבנה המשאבים.


מיפוי המשאבים מציב כל מיני דילמות, שאין להן תשובה חד משמעית:
  • כאשר אין קשר היררכיי ברור בין ה resources  - מה הסדר הנכון?
    • למשל: הזמנת-נסיעה ונהג - מי מכיל את מי? (בהנחה שכל אחד מהם הוא אובייקט שחי בפני עצמו. הזמנת-נסיעה נוצרת בלי קשר להשמה לנהג).
  • רזולוציה: האם למפות כל תכונה של אובייקט (למשל: title) לresource שיש לו URI משלו, או פשוט להסתפק ב sessions/update/ עבור כל התכונות יחדיו (בהתאם לפרמטרים שנשלחים בבקשה)?
  • כיצד לתאר גרסאות שונות של ה API? כחלק מה URI או כפרמטר?
  • ועוד...


רמה 2 - שימוש ב HTTP Verbs (ו Status Codes)

שימוש ב Method (נקראים גם Verbs) של פרוטוקול HTTP בכדי לתאר את הסמנטיקה של הפעולה:
  • GET - על מנת לבקש את ה state של המשאב אליו מפנה ה URI.
  • POST - על מנת לשלוח content ("נתונים"/"הודעה") למשאב לצורך עיבוד, עיבוד שייתכן וישנה את ה state של המשאב. לעתים הודעה זו תיצור תת-משאב (ואז נהוג להחזיר Status Code של 201 - "נוצר").
  • PUT - על מנת להחליף (rebind - "רישום מחדש") של התוכן של המשאב.
  • PATCH - על מנת לבצע עדכון חלקי של ה state של המשאב.
  • DELETE - על מנת למחוק את המשאב.
ניתן כמובן להשתמש גם במתודות האחרות של פרוטוקול ה HTTP,קרי HEAD, OPTIONS, TRACE - אולם הגדרת ההתנהגות שלהן עבור REST API היא פחות ברורה ויותר פתוחה לפרשנות.

כלל חשוב נוסף הוא שאין חובה לתמוך בכל 4 הפעולות הבסיסיות על כל משאב. ייתכן משאב שעליו ניתן לבצע רק GET ומשאב אחר שעליו אפשר לבצע רק POST. מצד שני הגדרת ה URI מחייבת שכל צומת מתאר משאב שניתן לגשת אליו. לדוגמה, אם הגדרתי משאב כ:

http://example.com/orders/2009/10/776654

אזי גם ה URIs הבאים צריכים להיות ברי-קיום:

http://example.com/orders/2009/10
http://example.com/orders/2009
http://example.com/orders
http://example.com

יתרון גדול בשימוש ב HTTP Verbs היא "קבלת Caching" בעלות מזערית. רכיבי רשת רבים: שרתי ווב, CDNs, רכיבי פרוקסי ו Gateway - מודעים ומכבדים את ה Verbs הללו. אם אנו עושים הרבה GET (ובעיקר: מוסיפים גם headers נכונים) - התשובה תהיה cached ב"רשת". כאשר נבצע POST לאותו משאב - ה caches יתנקו.

יתרון נוסף הוא שרכיבי אבטחת רשת IDS, WAF, ועוד - מודעים לבקשות הללו ול HTTP error codes - יודעים על פיהן להסיק ולזהות התנהגות חריגה / מסוכנת ברשת שלנו.

מה שכן דיי מעצבן הוא שלעתים רכיבים האבטחה מניחים שתשובות עם סטטוס 404 הם שגיאה ברורה - ונדירה מטבעה, אבל יכול להיות APIs שמחזירים 404 בצורה דיי תדירה (נניח: 10% מהפעמים) - ואז צריך או להרגיע (= לכוונן) את רכיב האבטחה או להימנע משימוש בקוד 404 ב API שלנו...

ההתנהגויות המוגדרות של HTTP verbs השונים. מקור: Lynda.com

עוד מידע על התנהגות ה HTTP הצפויה מה verbs השונים, ועל שימוש ב Status Codes - ניתן למצוא בפוסט על פרוטוקול ה HTTP.

כפי שתיארו את זה ריצרדסון ורובי בספר, הכוונה היא שפרוטוקול ה HTTP (או פרוטוקול אחר, רעיונות ה REST לא מתייחסים בהכרח ל HTTP) ישמש באותה המידה משתמשים אנושיים, ומכונות (צרכני API) באותה המידה ו(כמעט) באותו האופן:

"...Reunite the programmable web with the human Web... a World Wide Web that runs on one set of servers, uses one set of protocols, and obeys one set of design principles"
 -- Richardson & Ruby, RESTful web services, 2007.




רמה 3 - Hypermedia Controls

שמות נרדפים: Hypermedia transformations או Hypermedia As the Engine Of Application State (בקיצור: HATEOAS)

רעיון זה טוען שעל פעולה ב REST למשאב צריכה לתאר את פעולות ההמשך האפשריות כ links לפעולות הללו.
כשאנו גולשים באינטרנט, אנו הולכים למשאב מרכזי, למשל: https://www.bankhapoalim.co.il - ומשם אנו משתמשים בקישורים על מנת לבצע את שאר הפעולות: כניסה לחשבון, ביצוע העברה בנקאית, שליחת טופס לנציג הבנקאי האישי שביצענו טעות בהעברה הבנקאית (!!) - וכו'...

באופן דומה, הרעיון ב REST הוא שהתוכנה בצד השני (ה Client) לא "תדע" אלו פעולות זמינות, אלא תלמד אותן מהתשובה. למשל:



התשובה שלנו לכל קריאה, מכילה גם links שהם תיאור של הפעולות האפשריות. self למשל היא הפעולה הנוכחית, כאשר אני גם יכול לבצע product.search - ויש בידי את ה URI המתאים לביצוע התחזוקה.

עוד השלכה חשובה של ה HATEOAS היא שכל פנייה לשרת צריכה לפתוח בקריאת GET (או OPTIONS - לדקדקנים), ורק אחריה קריאת POST או PUT וכו'. יש מערכות שמסתמכות על ההנחה הזו.


משתמש אנושי יכול באמת להבין מה המשמעות של "product.search", אבל מה מכונה מבינה מזה? ישנן שתי אופציות:
  • המכונה מכירה את כל ערכי ה rel האפשריים - ולכן יודעת לפעול על פיהם.
  • המכונה לא מבינה.
הפער הזה נקרא ה Semantic Gap, עניין שאנשי ה Semantic Web (מספרם קצת הצטמצם בשנים האחרונות, לא?) - מנסים לפתור.

ישנם פרוטוקולים כמו XMDP או ALPS לתיאור סמנטיקה של פעולות API. מן שפות של meta descriptions.

מי שממשיך ומתקדם מעל רמה 3 - ראוי להיכנס להיכל התהילה של REST, כמי שיישם את מודל ה REST בצורתו הטהורה ביותר!



ספר על REST? - יש עשרות רבות...


מודל ה REST בפועל


האם זה הגיוני ליישם את שלב 3 במודל של ריצ'רדסון, Hypermedia Controls?
אם אתם מפתחים מערכת ווב טיפוסית - ברור שלא!

אם הגעתם ליישום של שלב 3 במערכת שכזו, כנראה שנכשלתם: נכשלתם ליישם מערכת פשוטה, שניתן לפתח במהירות.

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

דווקא ריצרדסון שהגדיר את מודל ה maturity ציין בראיונות מאוחרים יותר שהוא ניסה לספק שלבים כיצד לאמץ REST בהדרגה, ומבחינתו עצירה ברמות 1 או 2 - הן גם טובות.

לדעתי האישית, אין טעם ברמה 1 ללא רמה 2: מיפוי משאבים ללא שימוש ב Verbs הוא אנמי וחסר. הייתי ממליץ על רמה 2 או 0, עם הסתייגויות.

ההסתייגויות הן שכללים רבים של "REST טהור" עשויים להיות פשוט לא יעילים ליישום במערכת שלכם. הם יכולים לגזול זמן מיותר - ולספק מעט תועלת.

הנה כמה כללים שאנחנו נוהגים להתעלם מהם במערכת הקיימת שלנו (בידיעה):
  • הפער הגדול ביותר: אנו משתמשים בפעולות POST גם לצורך קריאות שלא משנות את ה state של האובייקט. פשוט כמו GET שמכיל payload גדול יותר, אפילו אם לא מתבצע processing מורכב מאחורי הקלעים.
    • זה אומר ששברנו כמה כללים של ה HTTP: חלק מקריאות ה POST הן עכשיו cacheable ו idempotent.
    • מצד שני: שרשור של פרמטרים ה URL זה פחות קל, ופחות קריא. הכי מעצבן היה לגלות שוב ושוב חסימות לאורך ה URL ברכיבי הרשת השונים: פעם ב WAF, פעם nginx - ופעם ב Load Balancer. אמנם אין הגבלה בתקן ה HTTP עצמו, אבל כנראה שבעקבות הדפדפנים שנהגו להגביל את אורך ה URL - נראה שגם רכיבי הרשת אמצו, כברירת מחדל, את המסורת...
  • לא כל חלק של URI הוא בר-תוקף. ייתכן וישנו URI בשם {companies/{id}/roles/{role_id/ מבלי שיש ל companies/{id}/roles/ כל תוקף. למה לנו לפתח API שאף אחד לא הולך לקרוא לו?
  • אנחנו משלבים שמות של פעולות, ולא רק משאבים ב URI. אנחנו משלבים אותן בסוף, כמעט-תמיד. למשל:
    areas/by_point ו areas/by_rectangle
  • אם פעולה יצרה משאב חדש, אנו לא מחזירים header של location עם ה URI למשאב שנוצר. הרבה יותר פשוט להחזיר id של האובייקט החדש בתוך ה JSON של התשובה.
  • ויש כנראה עוד...

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

כמו שאני נוהג להטיף, גם כאן אני מציע: השתמשו בכל כלי בצורה שהכי מועילה לכם, ולא ע"פ כלל שרשום איפשהו.

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

אנו כן מקפידים ב REST לשמור על הכללים הבסיסיים:
  • למדל בצורה סמנטית (קרי - ברורה מפתח) ובחשיבה על resources במבנה היררכי את URIs שאנו משתמשים בהם.
  • להקפיד על שימוש ב Verbs של HTTP ועל Status Codes בסמנטיקה שהוגדרה להם. אנו לא משתמשים ב Verbs ו Status Codes שאינם חלק מתקן ה HTTP (על אף שתקן ה HTTP עצמו - מותיר זאת).
  • להיות "Good Citizens", ולהתאים את התנהגות ה APIs שלנו לכללי ה HTTP במידת האפשר.

הנה במצגת הזו, תוכלו למצוא בין היתר דוגמאות לשימוש "לא תואם ל REST" ב APIs של חברות מוכרות. 
הייתי נמנע מרוב ה"שגיאות" שמוצגות, אך כנראה גם הייתי סולח ל.. עד מאמץ כמה מהן.
המצגת היא מ 2012, וחלק מה APIs שמוזכרים השתנו מאז, או אפילו לא קיימים יותר.




שיהיה בהצלחה!


---

קישורים רלוונטיים

הבלוג של מרטין פאוולר, על Richardson Maturity Model ו REST:
http://martinfowler.com/articles/richardsonMaturityModel.html

מצגת נחמדה שמתארת כמה מהבעיות שעלולות לצוץ ביישום REST (הרשאות, גרסאות שונות של API, טיפול בשגיאות, וכו'):
http://www.slideshare.net/MasoudKalali/masoudkalalirest-new-format


11 תגובות:

  1. שווה לתת סקירה על GraphQL, הכוכב החדש, כמתחרה חזק לגישת ה-REST.

    השבמחק
    תשובות
    1. תודה על ההערה!

      אני חושב שעוד מתמודד עכשווי הוא JSON API.

      לפני חמש שנים, כשכתבתי את הפוסט, היו ODATA ו GDATA (וגם AtomPub - עם גב יותר חלש) שניסו להחליף את REST - והיה להם מומנטום משמעותי.
      בסופו של דבר, הפשטות והגמישות של REST ניצחה את הפרוטוקולים המהונדסים הללו - ו REST נותר הפתרון הנפוץ ביותר.

      לא אתפלא בכלל אם זה גם מה שיקרה למתמודדים העכשוויים.
      למשל: ODATA (שקצת מזכיר את GraphQL - מלבד שהוא רלציוני) עזר ליצור APIs הרבה יותר שיטתיים וחד-משמעיים מ REST. הוא אפשר לעשות שאילתות מורכבות על גבי HTTP. קראו לו "SQL over HTTP", בכדי לתאר אותו בקצרה.

      זה היה כלי חזק ופרודקטיבי, עד שאנשים שמו לב ש:
      א. הנטייה האישית של רבים מאלו שעבדו עם ODATA הייתה לחשוף את המבנה הפנימי של המערכת שלהם, בצורה רחבה ופתוחה ב APIs. ההכמסה של השירות - התמוססה.
      ב. ניתן היה, ולכן נוצרו שאילתות מורכבות ב ODATA. עוד שיפור פה, ועוד מעקף לבאג שם - וחלק מהשאילתות הללו נעשו מסובכות ממש, ולא מובנות. לא היה מנגנון לתעד למה שדה x אסור שיהיה שווה 4 (כך היה בשאילתה) - ואז היה קל לאבד את השליטה על מה נעשה שם. השאילתות המורכבות הפכו במהרה ל legacy code שקשה לטפל בו.

      עכשיו, אני לא מכיר את GraphQL לעומק, וייתכן שה pitfalls שקודמיו נפלו בהם - הם לא רלוונטיים עבורו. כנראה שיהיו לו pitfalls חדשים משלו.

      האם הוא יחליף את REST? אני מוכן לחכות שנתיים ולראות.

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

      2 האגורות שלי,
      ליאור

      נ.ב. - אם אתה מכיר את GraphQL לעומק ומוכן לכתוב פוסט אורח - פנה אלי במייל (מופיע ב"אודות")!

      מחק
    2. אני אחדד את ההערה שלי: אני לא חושב שכרגע הוא מנסה להחליף את כל שימושי ה-REST, אלא מתמודד רק במקומות שבהם יש שימוש ב-REST כ-API פרטי בין הסרבר לבין קליינט SPA כלשהו.

      מה הבעיה של REST שמנסים לפתור? REST מייצר לך הרבה הרבה endpoints: אחת לכל משאב. ברגע שאתה מנסה לרנדר דף מורכב בקליינט, אתה צריך לאסוף הרבה מידע מהסרבר מהרבה מאד endpoints שונים, ולעשות סינטזה שלהם בצד הקליינט. הדבר גורר הרבה עבודה בצד הקליינט, סינכרון בין הרבה קריאות שרת (מה קורה אם אחת נכשלת?), וכמובן פגיעה בביצועים. לחילופין אפשר לייצר "mega-endpoint", פונקציה אחת בשרת שעושה בשבילך את כל העבודה ומחזירה לך מידע מורכב בקריאת שרת אחת. הבעיה בגישה הזו שזה כבר נוגד את רוח ה-REST, ובכך שמדובר בפיתוח ייעודי פר feature של הקליינט.

      הרעיון ב-GraphQL, על רגל אחת, הוא רק להגדיר את שפת השאילתות בין צד הלקוח לצד השרת. זה כמו SQL לאובייקטי JSON (אבל בלי קשר ל-HTTP), כאשר המימוש של אופן שליפת המידע בצד השרת נתון בידי המתכנת. כיוון שכך בסיס הנתונים עצמו יכול להיות כל דבר - RDBMS או NoSQL זה לא משנה - אפילו שרת Rest.

      אני לא מכיר ODATA, ואולי GraphQL ייכשל מאותן סיבות שציינת. אבל הבעיות של REST הן אמיתיות, כך שפתרון כלשהו צריך להגיע בסוף :)

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

      מחק
    3. תודה על התגובה!

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

      ליאור

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

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

      היתרון ב-GraphQL הוא בכך שאתה עובד ביחידות קטנות יותר בצד השרת, וצריך להגדיר רק משאבים פשוטים. בדוגמה הקודמת, נגדיר משאב REST נפרד לכל אחד מהמרכיבים של הדף בלבד - אין צורך במשאב כללי ברמת הדף כולו. ברגע שהקליינט יבקש לרנדר את הדף הוא יפנה לשרת GraphQL עם שאילתה שמתאימה ל-layout הרצוי, והשרת GraphQL ידאג לרוץ בין נקודות ה-REST השונות, להביא את המידע ולהחזיר את כל המידע בתור JSON אחד. כל זאת ב-request אחד כמובן.
      ומה יקרה אם נרצה לשנות את ה-layout? כל מה שצריך זה לעדכן את השאילתה בצד הלקוח בלבד. השרת אינו מושפע כלל.

      מחק
  2. היי ליאור, מאמר מעולה תודה!
    גם אנחנו עברנו תהליך דומה עם REST - היכרות, הטמעה, התפכחות.

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

    ציינת בתגובה הקודמת את JSON API (אני מניח שאתה מתייחס לפרוטוקול ה JSON RPC) - בהחלט מועמד טוב יותר למערכות המתאפיינות בביצוע פעולות ולא באחזור מידע. אפשר לראות גופים כמו slack ו bitcoin שמציעים את ה API שלהם כ RPC (ביטקוין משתמשים ב JSON RPC סטנדטי בגרסא 1.0 וב slack מגדירים פרוקטול משלהם).

    אנחנו מצאנו שלממשקים חיצוניים\פומביים עדיף להשתמש בממשקים REST-ים מכל הסיבות שציינת (כלים ,היכרות, אבטחה) ועבור ממשקים פנימיים עדיף להשתמש ב RPC.

    חקי.

    השבמחק
    תשובות
    1. תודה על התגובה!

      האמת שלא הכרתי את http://json-rpc.org . התכוונתי ל http://jsonapi.org

      ליאור

      מחק
  3. מאמר מצוין , תודה ליאור !

    השבמחק
  4. תגובה זו הוסרה על ידי המחבר.

    השבמחק
  5. תודה על המאמרים המצוינים!

    יצא לי להתעסק עם SOAP וREST
    ומה שאני התרשמתי שהמעבר הזה - זה הורדה של "עטיפה".

    SOAP זה שיטה של RPC. (- קריאה לפונקציה מרוחקת)
    באופן כללי הייתה מגמה של לדמות תכנות לאינטרנט כתכנות רגיל.
    המתכנת כותב פונקציות ומפעיל כלים אוטומטים בשביל לאפשר קריאה לפונקציה מרוחקת, כך שתחלופת ההודעות בין השרת ללקוח די מוסתרת מן המתכנת.
    בדומה לכך, ב-ASP.NET המתכנת לא מפעיל קריאות שרת באופן ישיר, אלא משתמש במערכת פקדים ואירועים שיוצרים זאת באופן אוטומטי.

    מסתבר שההמון העדיף לוותר על העטיפות האלה. ואנו רואים היום שימוש ישיר בפרוטוקול http.

    השבמחק