טיפים בנושא ביצועים

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

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

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

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

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

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

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

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

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

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

תשובה חלקית

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

כדי לבקש תגובה חלקית, משתמשים בפרמטר הבקשה 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, ומשתמשים ב-a/b/c כדי לבחור שדה c שמוטמע בשדה b.

    יוצא מן הכלל: בתגובות ל-API שמשתמשות במעטפות '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 משפיע על התגובה.

הערה: כמו כל ערכי הפרמטרים של השאילתה, ערך הפרמטר 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, הוא מחזיר קוד סטטוס 200 OK של HTTP, יחד עם הנתונים המבוקשים. אם יש שגיאה בפרמטר השאילתה 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), כדאי להשתמש בפרמטרים האלה כדי לצמצם את התוצאות של כל שאילתה לגודל שקל לנהל. אחרת, יכול להיות שלא תהיה עלייה בביצועים כמו במקרים שבהם נעשה שימוש בתגובה חלקית.

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

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

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

דוגמה

בדוגמה הזו מוצגת בקשת תיקון פשוטה לעדכון רק הכותרת של משאב API כללי (פיקטיבי) בשם Demo. למשאב יש גם תגובה, קבוצת מאפיינים, סטטוס ועוד הרבה שדות אחרים, אבל הבקשה הזו שולחת רק את השדה 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 נכלל בבקשת התיקון, זה הערך היחיד ששונה מהערך הקודם.

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

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

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

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

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

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

מומלץ להתחיל באחזור של תשובה חלקית עם הנתונים שרוצים לשנות. זה חשוב במיוחד למשאבים שמשתמשים ב-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 הקודם עם הבקשה כדי לעדכן את המשאב בהצלחה.

הערה: אפשר להשתמש ב"If-Match: *" כותרת HTTP כדי לאלץ תיקון לעבור כשמשתמשים ב-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 לא נתמך

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

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

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

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

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