חיבור מספר שרתי GraphQL עם Bramble
לפי האתר שלהם, בראמבל הם Production Ready GraphQL Federation. מאחר ואני תמיד שמח לבדוק חלופות פשוטות יותר ל Apollo הלכתי לבנות פרויקט דוגמה קטן עם בראמבל. קוד הפרויקט כאן: https://github.com/ynonp/playing-with-bramble
בפוסט אספר איך ברמבל עובד ומתי שווה לשקול אותו.
1. מה זה אומר GraphQL Federation
נניח שיש לכם מספר סרביסים שכל אחד מהם עובד ב GraphQL, ואתם רוצים לחשוף רק ממשק אחד לאפליקציית ה Front End שדרכו האפליקציה תוכל למשוך מידע מכל הסרביסים. במצב כזה אתם תרצו לבנות סרביס אחד שנקרא GraphQL Gateway שישתמש בסכימה שתהיה סוג-של-חיבור של כל הסכימות מכל הסרביסים, וכל פעם שנבקש ממנו מידע הוא פשוט יפנה לסרביס המתאים לקבל ממנו את המידע.
שתי הדרכים המרכזיות לחבר סכימות נקראות Schema stitching ו Federation כשההבדלים המרכזיים נוגעים לאופן שבו אנחנו מתיחסים לטיפוסים המשותפים בין סרביסים, ולאיך ממזגים את הסכימות. אומנם ברמבל הם פיתרון מסוג Federation אבל בפרויקט הדוגמה שכתבתי לא הגעתי לחלקים המעניינים של ה Federation של מיזוג טיפוסים ולכן לפחות מבחינת מה שנראה בפוסט הם היו יכולים באותה מידע לקרוא לזה Schema Stiching. מה שחשוב להבין כאן זה ש Bramble יהיה סוג של Gateway אוטומטי שפשוט מקבל את הסרביסים ויודע להעביר בקשות ולחבר מידע משניהם. ומה שאהבתי בו זה שהסטאפ היה מאוד מאוד פשוט.
2. הקמת שרת Bramble
כל מה שצריך בשביל להרים שרת Bramble הוא להריץ את הבינארי (כתוב ב go) ולהעביר לו קובץ קונפיגורציה שאומר איפה הסרביסים שהוא צריך לחבר. קובץ הקונפיגורציה שאני כתבתי נראה כך:
{
"services": [
"http://tasks-server:3000/graphql",
"http://fortune:3000/graphql"
],
"plugins": [
{
"name": "playground"
}
]
}
את הסכימות בראמבל מקבל מהסרביסים עצמם ולכן כל סרביס שצריך לשבת מאחורי בראמבל נדרש להוסיף ל Query שלו שאילתה שמחזירה טיפוס בשם Service.
בפרויקט הדוגמה יש לי שני סרביסים, אחד נקרא fortune שמחזיר את התוצאה של פקודת fortune והשני נקרא tasks-server שמחזיר רשימת משימות. קובץ הסכימה מתוך סרביס fortune שהוא הקטן יותר נראה כך:
type Query {
fortune: String!
service: Service!
}
type Service {
name: String! # unique name for the service
version: String! # any string
schema: String! # the full schema for the service
}
והחלק הרלוונטי בסכימה מסרביס המשימות נראה כך:
type Query {
tasks(done: Boolean): [Task]
task(id: String): Task
service: Service!
}
type Service {
name: String! # unique name for the service
version: String! # any string
schema: String! # the full schema for the service
}
גם ה Resolver עבור Service הוא די העתק-הדבק מהדוגמאות שלהם. הנה אחד שכתבתי לדוגמה בסרביס המשימות:
service(_obj, _args, _context, info) {
return {
name: 'Tasks',
version: '1.0',
schema: require('./schema.graphql'),
}
},
ובסך הכל זה כל מה שצריך בשביל שבראמבל יעבוד.
3. איך בראמבל עובד
בעליית הפרויקט ברמאבל מתחבר לסרביסים שהעברנו לו בקובץ הקונפיגורציה, לוקח את הסכימות מהם, בונה אוטומטית סכימה משותפת ומאפשר להתחיל להריץ שאילתות. אם אתם מורידים את פרויקט הדוגמה ורוצים לנסות את זה הפעילו מהתיקיה הראשית שלו:
$ docker-compose up
ואחרי זה כנסו בדפדפן ל localhost:8082/playground
.
אחרי זה תוכלו להריץ שאילתה כמו זו:
query a{
tasks {
text
}
}
ולקבל את רשימת המשימות או שאילתה כזו:
query b{
fortune
}
כדי לקבל fortune אקראי.
זה מדליק כי שתי השאילתות הולכות לאותו Gateway והוא כבר יודע לשלוח את השאילתה הראשונה לסרביס המשימות ואת השניה לסרביס ה fortune.
באותו Playground אפשר לראות גם את הסכימה המחוברת ובלוק Query שלה נראה כך:
type Query {
tasks(done: Boolean): [Task]
task(id: String): Task
fortune: String!
}
כלומר הוא חיבור של ה Query משני הסרביסים. את כל זה בראמבל הצליח לעשות אוטומטית.
4. מה עדיין לא הצלחתי לעשות
למרות קלות ההתקנה כשהסרביסים מכילים טיפוסים שונים, ממשחק קצר עם בראמבל לא הבנתי עד הסוף איך הם מטפלים בסרביסים שחולקים טיפוסים ודוגמאות שניסיתי לכתוב שהיו קצת יותר מסובכות ממה שהם הראו בתיעוד לא עבדו לי. לא בטוח אם הבעיה אצלי או בבראמבל, ויכול להיות שבהמשך כן אצליח להבין את מגננון שיתוף הטיפוסים שלהם.
בינתיים מה שאהבתי בפרויקט:
זיהוי מהיר של בעיות - כל פעם שהיתה לי טעות בראמבל הציג הודעה די אינפורמטיבית לקונסול
זיהוי מהיר ואוטומטי של כל הסרביסים ובניית סכימה מחוברת אונליין, כולל המשך מעקב אחרי הסרביסים ועדכון הסכימה אם משהו משתנה בסרביסים הפנימיים.
התקנה פשוטה דרך דוקר (בניתי אימג' בעצמי - האימג' שלהם לא עבד).
תמיכה מובנית באימות זהות דרך JWT
מה שלא אהבתי בפרויקט היה:
אין מספיק דוגמאות וגם התיעוד לא מקיף במיוחד.
ה Docker Image שהם מספקים לא עבד.
חלק מהאפשרויות בקונפיגורציה שכן הופיעו בתיעוד לא עבדו.
לא בטוח אם הדברים שלא עבדו היו בגלל שאני לא יודע להשתמש בפרויקט עדיין או בגלל שבאמת יש להם עדיין לא מעט באגים. בכל מקרה הפרויקט נראה צעיר ומבטיח. לא חושב שהיה לי אומץ להשתמש בו בפרודקשן במקום אפולו אבל בוודאות אחזור עוד כמה חודשים לבדוק מה מצבם.
זה הלינק לגיטהאב של בראמבל: https://github.com/movio/bramble
וזה פרויקט הדוגמה שלי שמשתמש בו עם שני סרביסים הכתובים ב Node.JS: https://github.com/ynonp/playing-with-bramble