טיפים לשיפור הביצועים

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

דחיסה באמצעות gzip

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

כדי לקבל תשובה בקידוד gzip, עליך לעשות שני דברים: להגדיר כותרת Accept-Encoding ולשנות את סוכן המשתמש כך שיכלול את המחרוזת gzip. לפניכם דוגמה לכותרות HTTP במבנה תקין שמאפשרות דחיסת gzip:

Accept-Encoding: gzip
User-Agent: my program (gzip)

עבודה עם משאבים חלקיים

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

יש שני סוגים של בקשות חלקיות:

  • תגובה חלקית: בקשה שבה מציינים אילו שדות יש לכלול בתגובה (באמצעות פרמטר הבקשה fields).
  • תיקון: בקשת עדכון שבה שולחים רק את השדות שרוצים לשנות (יש להשתמש בפועל PATCH של HTTP).

בקטעים הבאים יש פרטים נוספים על שליחת בקשות חלקיות.

תשובה חלקית

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

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

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

דוגמה

הדוגמה הבאה ממחישה את השימוש בפרמטר fields עם API גנרי (בדיוני) "Demo".

בקשה פשוטה: בקשת ה-HTTP GET מחסירה את הפרמטר fields ומחזירה את המשאב המלא.

https://www.googleapis.com/demo/v1

תגובת משאבים מלאה: נתוני המשאבים המלאים כוללים את השדות הבאים, לצד שדות רבים אחרים שהושמטו לצורך קיצור.

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

בקשה לתשובה חלקית: בבקשה הבאה לאותו משאב נעשה שימוש בפרמטר fields כדי להפחית באופן משמעותי את כמות הנתונים שמוחזרים.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

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

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

שימו לב שהתגובה היא אובייקט JSON שכולל רק את השדות שנבחרו ואת האובייקטים ההורה הסוגרים שלהם.

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

סיכום תחביר הפרמטרים של שדות

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

  • משתמשים ברשימה שמופרדת בפסיקים כדי לבחור כמה שדות.
  • משתמשים בפונקציה a/b כדי לבחור שדה b שמקונן בשדה a. כדי לבחור שדה c בתוך b צריך להשתמש בפונקציה a/b/c.

    חריג: בתגובות API שמשתמשות ברכיבי wrapper של "data", שבהן התגובה נמצאת בתוך אובייקט data שנראה כמו data: { ... }, אין לכלול את הערך 'data' במפרט fields. הכללת אובייקט הנתונים עם מפרט שדות כגון data/a/b גורמת לשגיאה. במקום זאת, צריך להשתמש במפרט של fields כמו a/b.

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

    לדוגמה: fields=items(id,author/email) מחזירה רק את מזהה הפריט ואת האימייל של המחבר לכל רכיב במערך הפריטים. אפשר גם לציין שדה משנה יחיד, שבו fields=items(id) מקביל ל-fields=items/id.

  • במקרה הצורך, אפשר להשתמש בתווים כלליים לחיפוש בשדות.

    לדוגמה: fields=items/pagemap/* בוחר את כל האובייקטים במפת דפים.

דוגמאות נוספות לשימוש בפרמטר השדות

בדוגמאות הבאות מוסבר איך ערך הפרמטר fields משפיע על התשובה.

הערה: כמו בכל ערכי הפרמטרים של שאילתות, ערך הפרמטר fields חייב להיות מקודד בכתובת ה-URL. כדי לשפר את הקריאות, הדוגמאות במסמך הזה לא כוללות את הקידוד.

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

הנה כמה דוגמאות ברמת האוסף:
דוגמאות השפעה
items מחזירה את כל הרכיבים במערך הפריטים, כולל כל השדות בכל רכיב, אבל לא שדות אחרים.
etag,items מחזירה גם את השדה etag וגם את כל הרכיבים במערך הפריטים.
items/title מחזירה רק את השדה title לכל הרכיבים במערך הפריטים.

בכל פעם ששדה בתוך שדה מוחזר, התגובה כוללת את האובייקטים ההורה הסוגרים. שדות ההורה לא כוללים שדות צאצא אחרים, אלא אם הם נבחרו גם באופן מפורש.
context/facets/label מחזירה רק את השדה label עבור כל האיברים במערך facets, שממוקם עצמו באובייקט context.
items/pagemap/*/title לכל רכיב במערך הפריטים, מחזירה רק את השדה title (אם קיים) של כל האובייקטים שהם צאצאים של pagemap.

הנה כמה דוגמאות ברמת המשאב:
דוגמאות השפעה
title מחזירה את השדה title של המשאב המבוקש.
author/uri מחזירה את שדה המשנה uri של האובייקט author במשאב המבוקש.
links/*/href
מחזירה את השדה href של כל האובייקטים שהם צאצאים של links.
אפשר לבקש רק חלקים משדות ספציפיים באמצעות בחירות משנה.
כברירת מחדל, אם הבקשה מציינת שדות מסוימים, השרת מחזיר את האובייקטים או את רכיבי המערך בשלמותם. אפשר לציין תשובה שכוללת רק שדות משנה מסוימים. אפשר לעשות זאת באמצעות התחביר של בחירת המשנה '( )', כמו בדוגמה שבהמשך.
דוגמה השפעה
items(title,author/uri) מחזירה רק את הערכים של title וה-uri של המחבר עבור כל רכיב במערך הפריטים.

טיפול בתגובות חלקיות

אחרי שהשרת מעבד בקשה חוקית שכוללת את פרמטר השאילתה fields, הוא שולח חזרה קוד סטטוס HTTP 200 OK יחד עם הנתונים המבוקשים. אם יש שגיאה בפרמטר של השאילתה fields או שהוא לא חוקי מסיבה אחרת, השרת מחזיר קוד סטטוס HTTP 400 Bad Request בצירוף הודעת שגיאה לגבי השגיאה בבחירת השדות (לדוגמה, "Invalid field selection a/b").

זוהי דוגמה לתשובה חלקית שמופיעה בקטע המבוא למעלה. הבקשה משתמשת בפרמטר fields כדי לציין אילו שדות להחזיר.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

התשובה החלקית נראית כך:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

הערה: בממשקי API שתומכים בפרמטרים של שאילתות בפילוח נתונים (maxResults ו-nextPageToken, למשל), כדאי להשתמש בפרמטרים האלה כדי לצמצם את התוצאות של כל שאילתה לגודל שניתן לניהול. אחרת, ייתכן שהביצועים ישיגו ביצועים חלקיים כי הם לא ייושמו.

תיקון (עדכון חלקי)

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

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

דוגמה

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

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

תשובה:

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

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

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

הסמנטיקה של בקשת תיקון

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

  • הוספה: כדי להוסיף שדה שלא קיים, מציינים את השדה החדש ואת הערך שלו.
  • שינוי: כדי לשנות את הערך של שדה קיים, מציינים את השדה ומגדירים אותו לערך החדש.
  • מחיקה: כדי למחוק שדה, מציינים אותו ומגדירים אותו לערך null. לדוגמה, "comment": null. אפשר גם למחוק אובייקט שלם (אם ניתן לשנות אותו) על ידי הגדרת הערך null. אם אתם משתמשים בספריית הלקוח של Java API, השתמשו במקום זאת ב-Data.NULL_STRING. לפרטים, קראו את JSON null.

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

שימוש בתיקון במחזור קריאה-שינוי-כתיבה

מומלץ להתחיל באחזור תשובה חלקית עם הנתונים שרוצים לשנות. זה חשוב במיוחד למשאבים שמשתמשים ב-ETags, כי עליך לספק את ערך ה-ETag הנוכחי בכותרת ה-HTTP של If-Match כדי לעדכן את המשאב בהצלחה. אחרי שמקבלים את הנתונים, אפשר לשנות את הערכים שרוצים לשנות ולשלוח בחזרה את הייצוג החלקי שהשתנה עם בקשת תיקון. הנה דוגמה שמתבססת על ההנחה שמשאב ההדגמה משתמש ב-ETags:

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

זוהי התשובה החלקית:

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

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

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

השרת מגיב עם קוד מצב HTTP 200 OK, והייצוג החלקי של המשאב המעודכן:

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

יצירה ישירה של בקשת תיקון

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

הערה: אפשר להשתמש בכותרת HTTP "If-Match: *" כדי לאלץ תיקון לעבור כשתגי ETags נמצאים בשימוש. אם עושים זאת, אין צורך לבצע את הקריאה לפני הכתיבה.

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

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

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

טיפול בתגובה לתיקון

לאחר עיבוד בקשת תיקון חוקית, ה-API מחזיר קוד תגובת HTTP מסוג 200 OK יחד עם הייצוג המלא של המשאב שהשתנה. אם ה-API משתמש ב-ETags, השרת מעדכן את ערכי ETag כשהוא מעבד בהצלחה בקשת תיקון, בדיוק כמו שהוא עושה עם PUT.

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

אם בקשת תיקון מובילה למצב משאב חדש שאינו תקין מבחינה תחבירית או סמנטית, השרת מחזיר קוד סטטוס HTTP של 400 Bad Request או 422 Unprocessable Entity ומצב המשאב נשאר ללא שינוי. לדוגמה, אם תנסו למחוק את הערך בשדה חובה, השרת יחזיר שגיאה.

סימון חלופי כשאין תמיכה בפועל HTTP של PATCH

אם חומת האש לא מאפשרת בקשות PATCH HTTP, צריך לבצע בקשת HTTP POST ולהגדיר את כותרת הביטול כ-PATCH, כפי שמוצג בהמשך:

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

ההבדל בין תיקון לעדכון

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

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