בקשות אצווה

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

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

סקירה כללית

כל חיבור HTTP שהלקוח שלך יוצר גורם לכמות מסוימת של תקורה. ה-API של Display & Video 360 תומך בקיבוץ באשכולות כדי לאפשר ללקוח שלכם להעביר מספר קריאות ל-API לבקשת HTTP אחת.

דוגמאות למצבים שבהם כדאי להשתמש בקיבוץ:

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

בכל מקרה, במקום לשלוח כל קריאה בנפרד, ניתן לקבץ את כל השיחות לבקשת HTTP אחת. כל הבקשות הפנימיות חייבות להגיע לאותו Google API.

אתה מוגבל ל-1,000 שיחות בבקשה אחת באצווה. אם צריך לבצע יותר שיחות, אפשר להשתמש במספר בקשות אצווה.

הערה: מערכת האצווה של Display & Video 360 API משתמשת באותו תחביר של מערכת עיבוד האצווה של OData, אבל הסמנטיקה שלה שונה.

פרטי הקבוצה

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

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

פורמט של בקשה באצווה

בקשה באצווה היא בקשת HTTP רגילה יחידה שמכילה כמה קריאות ל-API של Display & Video 360, שעושות שימוש בסוג התוכן multipart/mixed. בתוך בקשת ה-HTTP הראשית, כל אחד מהחלקים מכיל בקשת HTTP מקוננת.

כל חלק מתחיל בכותרת HTTP משלו מסוג Content-Type: application/http. אפשר גם להוסיף לו כותרת Content-ID אופציונלית. עם זאת, כותרות החלקים שם כדי לסמן את תחילת החלק. הן נפרדות מהבקשה המקוננת. לאחר שהשרת פותח את בקשת האצווה לבקשות נפרדות, המערכת מתעלמת מכותרות החלקים.

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

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

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

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

תגובה לבקשה לאצווה

תגובת השרת היא תגובת HTTP רגילה יחידה עם סוג תוכן multipart/mixed. כל חלק הוא התגובה לאחת מהבקשות שבבקשה המקובצת, באותו סדר של הבקשות.

בדומה לחלקים בבקשה, כל חלק תגובה מכיל תגובת HTTP מלאה, כולל קוד סטטוס, כותרות וגוף. וכמו החלקים שבבקשה, לפני כל חלק תגובה מופיעה כותרת Content-Type שמסמנת את תחילת החלק.

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

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

דוגמה

בדוגמה הבאה אפשר לראות את השימוש בקיבוץ ב-Display & Video 360 API.

דוגמה לבקשה בכמות גדולה

POST /batch HTTP/1.1
Host: displayvideo.googleapis.com
Authorization: Bearer your_auth_code
Content-Type: multipart/mixed; boundary=batch_foobarbaz
Content-Length: total_content_length

--batch_foobarbaz
Content-Type: application/http
Content-Transfer-Encoding: binary
MIME-Version: 1.0
Content-ID: <item1:12930812@displayvideo.example.com>

PATCH /v1/advertisers/advertiser_id?updateMask=displayName&fields=advertiserId,displayName HTTP/1.1
Content-Type: application/json; charset=UTF-8
Authorization: Bearer your_auth_code

{
  "displayName": "Updated Advertiser Name"
}
--batch_foobarbaz
Content-Type: application/http
Content-Transfer-Encoding: binary
MIME-Version: 1.0
Content-ID: <item2:12930812@displayvideo.example.com>

PATCH /v1/advertisers/advertiser_id/lineItems/line_item_id?updateMask=displayName&fields=lineItemId,displayName HTTP/1.1
Content-Type: application/json; charset=UTF-8
Authorization: Bearer your_auth_code

{
  "displayName": "Updated Line Item Name"
}

--batch_foobarbaz--

דוגמה לתשובה באצווה

זו התגובה לבקשה לדוגמה שצוינה בקטע הקודם.

HTTP/1.1 200
Content-Length: response_total_content_length
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item1:12930812@displayvideo.example.com>

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Content-Length: response_part_1_content_length

{
  "advertiserId": advertiser_id,
  "displayName": "Updated Advertiser Name"
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item2:12930812@displayvideo.example.com>

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Content-Length: response_part_2_content_length

{
  "lineItemId": line_item_id,
  "displayName": "Updated Line Item Name"
}

--batch_foobarbaz--

שימוש בספריות לקוח

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

Java

Long advertiserId = advertiser-id;
List<Long> lineItemIds = Arrays.asList(line-item-id-1, line-item-id-2);

BatchRequest batch = service.batch();
JsonBatchCallback<LineItem> callback = new JsonBatchCallback<LineItem>() {
  public void onSuccess(LineItem lineItem, HttpHeaders responseHeaders) {
    System.out.printf("Line Item '%s' is now active.\n",
        lineItem.getName());
  }

  public void onFailure (GoogleJsonError error, HttpHeaders responseHeaders)
      throws IOException{
    System.out.printf("Error activating line item: %s\n", error.getMessage());
  }
};

LineItem activatedLineItem = new LineItem().setEntityStatus("ENTITY_STATUS_ACTIVE");

for (Long lineItemId: lineItemIds) {
  service.advertisers().lineItems().patch(advertiserId, lineItemId, activatedLineItem)
      .setUpdateMask("entityStatus").queue(batch, callback);
}
batch.execute();

Python

advertiser_id = advertiser-id
line_item_ids = [line-item-id-1, line-item-id-2]

def callback(request_id, response, exception):
    if exception is not None:
        print('Error activating line item "%s": %s' %
              request_id, exception)
    else:
        print('Line item "%s" is now active.' %
              response.get('name'))

batch = service.new_batch_http_request(callback=callback)

line_item_obj = {
    'entityStatus': 'ENTITY_STATUS_ACTIVE'
}

for line_item_id in line_item_ids:
    request = service.advertisers().lineItems().patch(
        advertiserId=advertiser_id,
        lineItemId=line_item_id,
        updateMask="entityStatus",
        body=line_item_obj
    )
    batch.add(request, request_id=line_item_id)

batch.execute()

PHP

$advertiserId = advertiser-id;
$lineItemIds = array(line-item-id-1, line-item-id-2);

// Enable batching on client and create current batch
$service->getClient()->setUseBatch(true);
$batch = $service->createBatch();

// Create line item with updated fields
$updatedLineItem = new Google_Service_DisplayVideo_LineItem();
$updatedLineItem->setEntityStatus('ENTITY_STATUS_ACTIVE');

// Create request parameter array with update mask
$optParams = array('updateMask' => 'entityStatus');

// Add each patch request to the batch
foreach($lineItemIds as $lineItemId) {
    $request = $this->service->advertisers_lineItems->patch(
        $advertiserId,
        $lineItemId,
        $updatedLineItem,
        $optParams
    );
    $requestId = $lineItemId;
    $batch->add($request, $requestId);
}

// Execute batch request
$results = $batch->execute();

// Iterate through results
foreach($results as $responseId => $lineItem) {
    $lineItemId = substr($responseId, strlen('response-') + 1);
    if ($lineItem instanceof Google_Service_Exception) {
        $e = $lineItem;
        printf(
            "Error activating line item '%s': %s\n",
            $lineItemId,
            $e->getMessage()
        );
    } else {
        printf("Line item '%s' is now active.\n", $lineItem->getName());
    }
}
$service->getClient()->setUseBatch(false);