เคล็ดลับประสิทธิภาพ

เอกสารนี้ครอบคลุมเทคนิคบางอย่างที่คุณสามารถใช้เพื่อปรับปรุงประสิทธิภาพของแอปพลิเคชันของคุณ ในบางกรณี อาจมีการใช้ตัวอย่างจาก API อื่นๆ หรือ API ทั่วไปเพื่อแสดงให้เห็นแนวคิดที่นำเสนอ อย่างไรก็ตาม Google Wallet API ก็ใช้แนวคิดเดียวกันนี้ได้เช่นกัน

การบีบอัดโดยใช้ gzip

วิธีที่ง่ายและสะดวกในการลดแบนด์วิดท์ที่ต้องใช้สำหรับแต่ละคำขอคือการเปิดใช้การบีบอัด gzip แม้ว่าวิธีนี้ต้องใช้เวลา CPU เพิ่มเติมเพื่อยกเลิกการบีบอัดผลลัพธ์ แต่การแลกกับค่าใช้จ่ายเครือข่ายมักจะคุ้มค่ามาก

หากต้องการรับการตอบกลับที่เข้ารหัส gzip คุณต้องดำเนินการ 2 อย่าง ได้แก่ ตั้งค่าส่วนหัว Accept-Encoding และแก้ไข User Agent ให้มีสตริง gzip ตัวอย่างส่วนหัว HTTP ที่มีรูปแบบถูกต้องสำหรับเปิดใช้การบีบอัด gzip มีดังนี้

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

การทำงานกับทรัพยากรบางส่วน

อีกวิธีหนึ่งในการปรับปรุงประสิทธิภาพการเรียก API คือการส่งและรับเฉพาะข้อมูลที่คุณสนใจเท่านั้น ซึ่งช่วยให้แอปพลิเคชันหลีกเลี่ยงการโอน แยกวิเคราะห์ และจัดเก็บช่องที่ไม่จำเป็นได้ เพื่อให้ใช้ทรัพยากรต่างๆ รวมถึงเครือข่าย, CPU และหน่วยความจำได้อย่างมีประสิทธิภาพมากขึ้น

คำขอบางส่วนมี 2 ประเภท ได้แก่

  • การตอบกลับบางส่วน: คำขอที่คุณระบุช่องที่จะรวมไว้ในการตอบกลับ (ใช้พารามิเตอร์คำขอ fields)
  • แพตช์: คำขออัปเดตที่คุณส่งเฉพาะช่องที่ต้องการเปลี่ยน (ใช้คำกริยา HTTP ของ PATCH)

รายละเอียดเพิ่มเติมเกี่ยวกับการส่งคำขอบางส่วนจะแสดงในส่วนต่อไปนี้

คำตอบเพียงบางส่วน

โดยค่าเริ่มต้น เซิร์ฟเวอร์จะส่งการแสดงผลแบบเต็มของทรัพยากรกลับมาหลังจากประมวลผลคำขอ เพื่อประสิทธิภาพที่ดีขึ้น คุณสามารถขอให้เซิร์ฟเวอร์ส่งเฉพาะช่องที่คุณต้องการจริงๆ แล้วรับการตอบกลับบางส่วนแทน

หากต้องการขอการตอบกลับบางส่วน ให้ใช้พารามิเตอร์คำขอ fields เพื่อระบุช่องที่คุณต้องการให้แสดงผล คุณใช้พารามิเตอร์นี้กับคำขอใดก็ได้ที่แสดงข้อมูลการตอบกลับ

โปรดทราบว่าพารามิเตอร์ fields จะส่งผลต่อข้อมูลการตอบกลับเท่านั้น จะไม่ส่งผลต่อข้อมูลที่คุณต้องส่ง (หากมี) หากต้องการลดปริมาณข้อมูลที่คุณส่งเมื่อแก้ไขทรัพยากร ให้ใช้คำขอแพตช์

ตัวอย่าง

ตัวอย่างต่อไปนี้แสดงการใช้พารามิเตอร์ fields กับ "การสาธิต" ทั่วไป (สมมติ) API

คำขอแบบง่าย: คำขอ 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 ที่ใช้ "ข้อมูล" Wrapper ที่การตอบสนองฝังอยู่ในออบเจ็กต์ data ที่มีลักษณะคล้ายกับ data: { ... } ไม่ต้องรวม "data" ในข้อกำหนดจำเพาะ fields การรวมออบเจ็กต์ข้อมูลตามข้อกำหนดของช่อง เช่น data/a/b จะทำให้เกิดข้อผิดพลาด แต่ให้ใช้ข้อกำหนดของ fields เช่น a/b แทน

  • ใช้ตัวเลือกย่อยเพื่อขอชุดฟิลด์ย่อยของอาร์เรย์หรือวัตถุที่ระบุ โดยวางนิพจน์ในวงเล็บ "( )"

    เช่น fields=items(id,author/email) จะแสดงเฉพาะรหัสสินค้าและอีเมลของผู้เขียนสำหรับองค์ประกอบแต่ละรายการในอาร์เรย์ items คุณยังระบุช่องย่อยช่องเดียวได้ด้วย โดย fields=items(id) มีค่าเท่ากับ fields=items/id

  • ใช้ไวลด์การ์ดในการเลือกช่อง หากจำเป็น

    เช่น fields=items/pagemap/* เลือกออบเจ็กต์ทั้งหมดในแผนที่หน้าเว็บ

ตัวอย่างเพิ่มเติมของการใช้พารามิเตอร์ "ฟิลด์"

ตัวอย่างด้านล่างจะมีคำอธิบายว่าค่าพารามิเตอร์ fields ส่งผลต่อการตอบกลับอย่างไร

หมายเหตุ: เช่นเดียวกับค่าพารามิเตอร์การค้นหาทั้งหมด ค่าพารามิเตอร์ fields ต้องเป็น URL ที่เข้ารหัส ตัวอย่างในเอกสารนี้ละเว้นการเข้ารหัสเพื่อให้อ่านง่ายขึ้น

ระบุช่องที่คุณต้องการให้แสดงผล หรือทำเลือกช่อง
ค่าพารามิเตอร์คำขอ fields คือรายการช่องที่คั่นด้วยคอมมา และมีการระบุแต่ละช่องซึ่งสัมพันธ์กับรูทของการตอบกลับ ดังนั้นถ้าคุณดำเนินการ list การตอบกลับจะเป็นคอลเล็กชัน และโดยทั่วไปจะประกอบด้วยอาร์เรย์ของทรัพยากร หากคุณกำลังดำเนินการที่ส่งคืนทรัพยากรเดียว จะมีการระบุช่องซึ่งสัมพันธ์กับทรัพยากรนั้น ถ้าช่องที่คุณเลือกเป็น (หรือเป็นส่วนหนึ่งของ) อาร์เรย์ เซิร์ฟเวอร์จะส่งคืนส่วนที่เลือกขององค์ประกอบทั้งหมดในอาร์เรย์

ตัวอย่างระดับคอลเล็กชันบางส่วนมีดังนี้
ตัวอย่าง ผลกระทบ
items แสดงผลองค์ประกอบทั้งหมดในอาร์เรย์ items โดยรวมช่องทั้งหมดในแต่ละองค์ประกอบ แต่ไม่แสดงช่องอื่นๆ
etag,items แสดงผลทั้งฟิลด์ etag และองค์ประกอบทั้งหมดในอาร์เรย์ items
items/title แสดงผลเฉพาะช่อง title สำหรับองค์ประกอบทั้งหมดในอาร์เรย์ items

เมื่อใดก็ตามที่มีการส่งคืนช่องที่ซ้อนกัน การตอบสนองจะรวมออบเจ็กต์หลักที่ล้อมรอบอยู่ ช่องหลักไม่มีช่องย่อยอื่นๆ เว้นแต่จะเลือกไว้อย่างชัดเจน
context/facets/label แสดงผลเฉพาะช่อง label สำหรับสมาชิกทั้งหมดของอาร์เรย์ facets ซึ่งฝังอยู่ใต้ออบเจ็กต์ context
items/pagemap/*/title สำหรับองค์ประกอบแต่ละรายการในอาร์เรย์ items จะแสดงเฉพาะช่อง title (หากมี) ของออบเจ็กต์ทั้งหมดที่เป็นระดับย่อยของ pagemap

ตัวอย่างระดับแหล่งข้อมูลบางส่วนมีดังนี้
ตัวอย่าง ผลกระทบ
title แสดงผลฟิลด์ title ของทรัพยากรที่ขอ
author/uri แสดงผลฟิลด์ย่อย uri ของออบเจ็กต์ author ในทรัพยากรที่ขอ
links/*/href
แสดงผลฟิลด์ href ของออบเจ็กต์ทั้งหมดที่เป็นรายการย่อยของ links
ขอเฉพาะบางช่องโดยใช้การเลือกย่อย
โดยค่าเริ่มต้น หากคำขอของคุณระบุช่องเฉพาะ เซิร์ฟเวอร์จะส่งกลับออบเจ็กต์หรือองค์ประกอบอาร์เรย์ทั้งหมด คุณระบุการตอบกลับที่มีเฉพาะช่องย่อยบางช่องได้ คุณดำเนินการนี้โดยใช้ "( )" ไวยากรณ์การเลือกย่อย ดังที่แสดงในตัวอย่างด้านล่าง
ตัวอย่าง ผลกระทบ
items(title,author/uri) แสดงผลเฉพาะค่าของ title และ uri ของผู้เขียนสำหรับแต่ละองค์ประกอบในอาร์เรย์ items

การจัดการคำตอบบางส่วน

หลังจากที่เซิร์ฟเวอร์ประมวลผลคำขอที่ถูกต้องซึ่งมีพารามิเตอร์การค้นหา 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) ให้ใช้พารามิเตอร์เหล่านั้นเพื่อลดผลลัพธ์ของการค้นหาแต่ละรายการให้เป็นขนาดที่จัดการได้ มิฉะนั้น ประสิทธิภาพจะเพิ่มขึ้นเมื่อใช้การตอบกลับบางส่วน

แพตช์ (อัปเดตบางส่วน)

นอกจากนี้ คุณยังหลีกเลี่ยงการส่งข้อมูลที่ไม่จำเป็นเมื่อแก้ไขทรัพยากรได้ด้วย หากต้องการส่งข้อมูลที่อัปเดตแล้วเฉพาะสำหรับช่องที่คุณกำลังเปลี่ยนแปลงเท่านั้น ให้ใช้คำกริยา HTTP PATCH ความหมายของแพตช์ที่อธิบายไว้ในเอกสารนี้จะแตกต่าง (และง่ายกว่า) สำหรับการติดตั้งใช้งาน 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 การตอบสนองบางส่วน ร่วมกับแพตช์ คุณจะเพิ่มประสิทธิภาพของคำขออัปเดตได้มากขึ้นไปอีก คำขอแพตช์จะลดขนาดคำขอเท่านั้น คำตอบบางส่วนจะลดขนาดคำตอบลง ดังนั้นหากต้องการลดปริมาณข้อมูลที่ส่งในทั้ง 2 ทิศทาง ให้ใช้คำขอแพตช์ที่มีพารามิเตอร์ fields

ความหมายของคำขอแพตช์

เนื้อหาของคำขอแพตช์จะมีเฉพาะช่องทรัพยากรที่คุณต้องการแก้ไข เมื่อระบุช่อง คุณต้องรวมออบเจ็กต์หลักที่ล้อมรอบด้วยจะต้องแสดงผลออบเจ็กต์หลักที่ล้อมรอบด้วยคำตอบบางส่วน ข้อมูลที่แก้ไขที่คุณส่งจะรวมกันเป็นข้อมูลสำหรับออบเจ็กต์หลัก หากมี

  • เพิ่ม: หากต้องการเพิ่มช่องที่ยังไม่มีในระบบ ให้ระบุช่องใหม่และค่าในช่อง
  • แก้ไข: หากต้องการเปลี่ยนค่าของช่องที่มีอยู่ ให้ระบุช่องดังกล่าวและตั้งเป็นค่าใหม่
  • ลบ: หากต้องการลบช่อง ให้ระบุช่องนั้นแล้วตั้งค่าเป็น null เช่น "comment": null นอกจากนี้ คุณยังลบออบเจ็กต์ทั้งหมด (หากเปลี่ยนแปลงไม่ได้) โดยการตั้งค่าเป็น null ได้ด้วย หากคุณกำลังใช้ ไลบรารีของไคลเอ็นต์ Java API ให้ใช้ Data.NULL_STRING แทน สำหรับ โปรดดูรายละเอียดที่หัวข้อ JSON null

หมายเหตุเกี่ยวกับอาร์เรย์: คำขอแพตช์ที่มีอาร์เรย์จะแทนที่อาร์เรย์ที่มีอยู่ด้วยอาร์เรย์ที่คุณระบุ คุณไม่สามารถแก้ไข เพิ่ม หรือลบรายการในอาร์เรย์แบบเป็นส่วนๆ ได้

การใช้แพตช์ในรอบการอ่าน-แก้ไข-เขียน

วิธีนี้อาจเป็นประโยชน์หากคุณเริ่มต้นโดยการดึงข้อมูลคำตอบบางส่วนพร้อมข้อมูลที่ต้องการแก้ไข ข้อมูลนี้สำคัญอย่างยิ่งสำหรับทรัพยากรที่ใช้ ETag เนื่องจากคุณต้องระบุค่า ETag ปัจจุบันในส่วนหัว HTTP If-Match เพื่ออัปเดตทรัพยากรให้สำเร็จ หลังจากที่ได้รับข้อมูลแล้ว คุณจะแก้ไขค่าที่ต้องการเปลี่ยนแปลงและส่งการแสดงส่วนที่แก้ไขบางส่วนกลับมาพร้อมคำขอแพตช์ได้ ตัวอย่างสมมติให้ทรัพยากรเดโมใช้ ETag มีดังนี้

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 ใช้ ETag คุณต้องส่งค่า ETag ก่อนหน้าไปกับคําขอเพื่อให้อัปเดตทรัพยากรได้สําเร็จ

หมายเหตุ: คุณใช้ส่วนหัว HTTP ของ "If-Match: *" เพื่อบังคับให้แพตช์ผ่านได้เมื่อใช้งาน ETag หากคุณทำเช่นนี้ ก็ไม่จำเป็นต้องอ่านก่อนเขียน

อย่างไรก็ตาม สำหรับสถานการณ์อื่นๆ คุณสามารถสร้างคำขอแพตช์ได้โดยตรงโดยไม่ต้องเรียกข้อมูลที่มีอยู่ก่อน ตัวอย่างเช่น คุณสามารถสร้างคำขอแพตช์ที่อัปเดตช่องเป็นค่าใหม่หรือเพิ่มช่องใหม่ มีตัวอย่างดังต่อไปนี้

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 จะส่งคืนรหัสการตอบกลับ 200 OK HTTP พร้อมกับการแสดงทรัพยากรที่แก้ไขอย่างสมบูรณ์ หาก API ใช้ ETag เซิร์ฟเวอร์จะอัปเดตค่า 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 จะทำให้คำขอล้มเหลวหากคุณไม่ใส่พารามิเตอร์ที่จำเป็น และจะล้างข้อมูลที่ตั้งค่าไว้ก่อนหน้านี้หากไม่ได้ระบุพารามิเตอร์ที่ไม่บังคับ

การใช้แพตช์จึงปลอดภัยกว่ามาก คุณให้ข้อมูลสำหรับช่องที่ต้องการเปลี่ยนแปลงเท่านั้น ระบบจะไม่ล้างช่องที่คุณยกเว้น ข้อยกเว้นเพียงอย่างเดียวของกฎนี้จะเกิดขึ้นกับองค์ประกอบหรืออาร์เรย์ที่ซ้ำกัน: ถ้าคุณข้ามทั้งหมด องค์ประกอบหรืออาร์เรย์ทั้งหมดจะยังเหมือนเดิม หากมีผลิตภัณฑ์ใดๆ ก็ตาม ทั้งชุดจะแทนที่ด้วยชุดที่คุณให้ไว้

คำขอแบบกลุ่มไปยัง Google Wallet

Google Wallet API รองรับการเรียก API แบบกลุ่มพร้อมกันเพื่อลดจำนวนหมายเลข ที่ไคลเอ็นต์จะต้องทำอีก ดูข้อมูลเพิ่มเติมเกี่ยวกับคำขอแบบกลุ่มและ โปรดดูโครงสร้างการตอบกลับในรายละเอียดกลุ่ม

โค้ดตัวอย่างต่อไปนี้แสดงคำขอแบบกลุ่ม Java และ PHP ตัวอย่างเช่น ให้ใช้แท็บ Google Wallet ไลบรารีเพื่อลดความซับซ้อนในการสร้างคลาสและออบเจ็กต์

Java

หากต้องการเริ่มการผสานรวมของคุณใน Java โปรดดู ตัวอย่างโค้ดใน GitHub

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 */
public void batchCreateObjects(String issuerId, String classSuffix) throws IOException {
  // Create the batch request client
  BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));

  // The callback will be invoked for each request in the batch
  JsonBatchCallback<OfferObject> callback =
      new JsonBatchCallback<OfferObject>() {
        // Invoked if the request was successful
        public void onSuccess(OfferObject response, HttpHeaders responseHeaders) {
          System.out.println("Batch insert response");
          System.out.println(response.toString());
        }

        // Invoked if the request failed
        public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
          System.out.println("Error Message: " + e.getMessage());
        }
      };

  // Example: Generate three new pass objects
  for (int i = 0; i < 3; i++) {
    // Generate a random object suffix
    String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
    OfferObject batchObject =
        new OfferObject()
            .setId(String.format("%s.%s", issuerId, objectSuffix))
            .setClassId(String.format("%s.%s", issuerId, classSuffix))
            .setState("ACTIVE")
            .setHeroImage(
                new Image()
                    .setSourceUri(
                        new ImageUri()
                            .setUri(
                                "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                    .setContentDescription(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString()
                                    .setLanguage("en-US")
                                    .setValue("Hero image description"))))
            .setTextModulesData(
                    List.of(
                            new TextModuleData()
                                    .setHeader("Text module header")
                                    .setBody("Text module body")
                                    .setId("TEXT_MODULE_ID")))
            .setLinksModuleData(
                new LinksModuleData()
                    .setUris(
                        Arrays.asList(
                            new Uri()
                                .setUri("http://maps.google.com/")
                                .setDescription("Link module URI description")
                                .setId("LINK_MODULE_URI_ID"),
                            new Uri()
                                .setUri("tel:6505555555")
                                .setDescription("Link module tel description")
                                .setId("LINK_MODULE_TEL_ID"))))
            .setImageModulesData(
                    List.of(
                            new ImageModuleData()
                                    .setMainImage(
                                            new Image()
                                                    .setSourceUri(
                                                            new ImageUri()
                                                                    .setUri(
                                                                            "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                                                    .setContentDescription(
                                                            new LocalizedString()
                                                                    .setDefaultValue(
                                                                            new TranslatedString()
                                                                                    .setLanguage("en-US")
                                                                                    .setValue("Image module description"))))
                                    .setId("IMAGE_MODULE_ID")))
            .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
            .setLocations(
                    List.of(
                            new LatLongPoint()
                                    .setLatitude(37.424015499999996)
                                    .setLongitude(-122.09259560000001)))
            .setValidTimeInterval(
                new TimeInterval()
                    .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z"))
                    .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z")));

    service.offerobject().insert(batchObject).queue(batch, callback);
  }

  // Invoke the batch API calls
  batch.execute();
}

PHP

หากต้องการเริ่มการผสานรวมใน PHP โปรดดู ตัวอย่างโค้ดใน GitHub

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for the pass class.
 */
public function batchCreateObjects(string $issuerId, string $classSuffix)
{
  // Update the client to enable batch requests
  $this->client->setUseBatch(true);
  $batch = $this->service->createBatch();

  // Example: Generate three new pass objects
  for ($i = 0; $i < 3; $i++) {
    // Generate a random object suffix
    $objectSuffix = preg_replace('/[^\w.-]/i', '_', uniqid());

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
    $batchObject = new OfferObject([
      'id' => "{$issuerId}.{$objectSuffix}",
      'classId' => "{$issuerId}.{$classSuffix}",
      'state' => 'ACTIVE',
      'heroImage' => new Image([
        'sourceUri' => new ImageUri([
          'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
        ]),
        'contentDescription' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => 'Hero image description'
          ])
        ])
      ]),
      'textModulesData' => [
        new TextModuleData([
          'header' => 'Text module header',
          'body' => 'Text module body',
          'id' => 'TEXT_MODULE_ID'
        ])
      ],
      'linksModuleData' => new LinksModuleData([
        'uris' => [
          new Uri([
            'uri' => 'http://maps.google.com/',
            'description' => 'Link module URI description',
            'id' => 'LINK_MODULE_URI_ID'
          ]),
          new Uri([
            'uri' => 'tel:6505555555',
            'description' => 'Link module tel description',
            'id' => 'LINK_MODULE_TEL_ID'
          ])
        ]
      ]),
      'imageModulesData' => [
        new ImageModuleData([
          'mainImage' => new Image([
            'sourceUri' => new ImageUri([
              'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
            ]),
            'contentDescription' => new LocalizedString([
              'defaultValue' => new TranslatedString([
                'language' => 'en-US',
                'value' => 'Image module description'
              ])
            ])
          ]),
          'id' => 'IMAGE_MODULE_ID'
        ])
      ],
      'barcode' => new Barcode([
        'type' => 'QR_CODE',
        'value' => 'QR code value'
      ]),
      'locations' => [
        new LatLongPoint([
          'latitude' => 37.424015499999996,
          'longitude' =>  -122.09259560000001
        ])
      ],
      'validTimeInterval' => new TimeInterval([
        'start' => new DateTime([
          'date' => '2023-06-12T23:20:50.52Z'
        ]),
        'end' => new DateTime([
          'date' => '2023-12-12T23:20:50.52Z'
        ])
      ])
    ]);

    $batch->add($this->service->offerobject->insert($batchObject));
  }

  // Make the batch request
  $batchResponse = $batch->execute();

  print "Batch insert response\n";
  foreach ($batchResponse as $key => $value) {
    if ($value instanceof Google_Service_Exception) {
      print_r($value->getErrors());
      continue;
    }
    print "{$value->getId()}\n";
  }
}

Python

หากต้องการเริ่มการผสานรวมใน Python โปรดดู ตัวอย่างโค้ดใน GitHub

def batch_create_objects(self, issuer_id: str, class_suffix: str):
    """Batch create Google Wallet objects from an existing class.

    The request body will be a multiline string. See below for information.

    https://cloud.google.com/compute/docs/api/how-tos/batch#example

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for this pass class.
    """
    batch = self.client.new_batch_http_request()

    # Example: Generate three new pass objects
    for _ in range(3):
        # Generate a random object suffix
        object_suffix = str(uuid.uuid4()).replace('[^\\w.-]', '_')

        # See link below for more information on required properties
        # https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
        batch_object = {
            'id': f'{issuer_id}.{object_suffix}',
            'classId': f'{issuer_id}.{class_suffix}',
            'state': 'ACTIVE',
            'heroImage': {
                'sourceUri': {
                    'uri':
                        'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Hero image description'
                    }
                }
            },
            'textModulesData': [{
                'header': 'Text module header',
                'body': 'Text module body',
                'id': 'TEXT_MODULE_ID'
            }],
            'linksModuleData': {
                'uris': [{
                    'uri': 'http://maps.google.com/',
                    'description': 'Link module URI description',
                    'id': 'LINK_MODULE_URI_ID'
                }, {
                    'uri': 'tel:6505555555',
                    'description': 'Link module tel description',
                    'id': 'LINK_MODULE_TEL_ID'
                }]
            },
            'imageModulesData': [{
                'mainImage': {
                    'sourceUri': {
                        'uri':
                            'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                    },
                    'contentDescription': {
                        'defaultValue': {
                            'language': 'en-US',
                            'value': 'Image module description'
                        }
                    }
                },
                'id': 'IMAGE_MODULE_ID'
            }],
            'barcode': {
                'type': 'QR_CODE',
                'value': 'QR code'
            },
            'locations': [{
                'latitude': 37.424015499999996,
                'longitude': -122.09259560000001
            }],
            'validTimeInterval': {
                'start': {
                    'date': '2023-06-12T23:20:50.52Z'
                },
                'end': {
                    'date': '2023-12-12T23:20:50.52Z'
                }
            }
        }

        batch.add(self.client.offerobject().insert(body=batch_object))

    # Invoke the batch API calls
    response = batch.execute()

    print('Batch complete')

C#

หากต้องการเริ่มการผสานรวมใน C# โปรดดู ตัวอย่างโค้ดใน GitHub

/// <summary>
/// Batch create Google Wallet objects from an existing class.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
public async void BatchCreateObjects(string issuerId, string classSuffix)
{
  // The request body will be a multiline string
  // See below for more information
  // https://cloud.google.com/compute/docs/api/how-tos/batch//example
  string data = "";

  HttpClient httpClient = new HttpClient();
  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer",
    credentials.GetAccessTokenForRequestAsync().Result
  );

  // Example: Generate three new pass objects
  for (int i = 0; i < 3; i++)
  {
    // Generate a random object suffix
    string objectSuffix = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_");

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
    OfferObject batchObject = new OfferObject
    {
      Id = $"{issuerId}.{objectSuffix}",
      ClassId = $"{issuerId}.{classSuffix}",
      State = "ACTIVE",
      HeroImage = new Image
      {
        SourceUri = new ImageUri
        {
          Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
        },
        ContentDescription = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "Hero image description"
          }
        }
      },
      TextModulesData = new List<TextModuleData>
      {
        new TextModuleData
        {
          Header = "Text module header",
          Body = "Text module body",
          Id = "TEXT_MODULE_ID"
        }
      },
      LinksModuleData = new LinksModuleData
      {
        Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
        {
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "http://maps.google.com/",
            Description = "Link module URI description",
            Id = "LINK_MODULE_URI_ID"
          },
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "tel:6505555555",
            Description = "Link module tel description",
            Id = "LINK_MODULE_TEL_ID"
          }
        }
      },
      ImageModulesData = new List<ImageModuleData>
      {
        new ImageModuleData
        {
          MainImage = new Image
          {
            SourceUri = new ImageUri
            {
              Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
            },
            ContentDescription = new LocalizedString
            {
              DefaultValue = new TranslatedString
              {
                Language = "en-US",
                Value = "Image module description"
              }
            }
          },
          Id = "IMAGE_MODULE_ID"
        }
      },
      Barcode = new Barcode
      {
        Type = "QR_CODE",
        Value = "QR code"
      },
      Locations = new List<LatLongPoint>
      {
        new LatLongPoint
        {
          Latitude = 37.424015499999996,
          Longitude = -122.09259560000001
        }
      },
      ValidTimeInterval = new TimeInterval
      {
        Start = new Google.Apis.Walletobjects.v1.Data.DateTime
        {
          Date = "2023-06-12T23:20:50.52Z"
        },
        End = new Google.Apis.Walletobjects.v1.Data.DateTime
        {
          Date = "2023-12-12T23:20:50.52Z"
        }
      }
    };

    data += "--batch_createobjectbatch\n";
    data += "Content-Type: application/json\n\n";
    data += "POST /walletobjects/v1/offerObject/\n\n";

    data += JsonConvert.SerializeObject(batchObject) + "\n\n";
  }
  data += "--batch_createobjectbatch--";

  // Invoke the batch API calls
  HttpRequestMessage batchObjectRequest = new HttpRequestMessage(
      HttpMethod.Post,
      "https://walletobjects.googleapis.com/batch");

  batchObjectRequest.Content = new StringContent(data);
  batchObjectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(
      "multipart/mixed");
  // `boundary` is the delimiter between API calls in the batch request
  batchObjectRequest.Content.Headers.ContentType.Parameters.Add(
      new NameValueHeaderValue("boundary", "batch_createobjectbatch"));

  HttpResponseMessage batchObjectResponse = httpClient.Send(
      batchObjectRequest);

  string batchObjectContent = await batchObjectResponse
      .Content
      .ReadAsStringAsync();

  Console.WriteLine("Batch insert response");
  Console.WriteLine(batchObjectContent);
}

Node.js

หากต้องการเริ่มการผสานรวมในโหนด โปรดดู ตัวอย่างโค้ดใน GitHub

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for this pass class.
 */
async batchCreateObjects(issuerId, classSuffix) {
  // See below for more information
  // https://cloud.google.com/compute/docs/api/how-tos/batch#example
  let data = '';
  let batchObject;
  let objectSuffix;

  // Example: Generate three new pass objects
  for (let i = 0; i < 3; i++) {
    // Generate a random object suffix
    objectSuffix = uuidv4().replace('[^\w.-]', '_');

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
    batchObject = {
      'id': `${issuerId}.${objectSuffix}`,
      'classId': `${issuerId}.${classSuffix}`,
      'state': 'ACTIVE',
      'heroImage': {
        'sourceUri': {
          'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
        },
        'contentDescription': {
          'defaultValue': {
            'language': 'en-US',
            'value': 'Hero image description'
          }
        }
      },
      'textModulesData': [
        {
          'header': 'Text module header',
          'body': 'Text module body',
          'id': 'TEXT_MODULE_ID'
        }
      ],
      'linksModuleData': {
        'uris': [
          {
            'uri': 'http://maps.google.com/',
            'description': 'Link module URI description',
            'id': 'LINK_MODULE_URI_ID'
          },
          {
            'uri': 'tel:6505555555',
            'description': 'Link module tel description',
            'id': 'LINK_MODULE_TEL_ID'
          }
        ]
      },
      'imageModulesData': [
        {
          'mainImage': {
            'sourceUri': {
              'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
            },
            'contentDescription': {
              'defaultValue': {
                'language': 'en-US',
                'value': 'Image module description'
              }
            }
          },
          'id': 'IMAGE_MODULE_ID'
        }
      ],
      'barcode': {
        'type': 'QR_CODE',
        'value': 'QR code'
      },
      'locations': [
        {
          'latitude': 37.424015499999996,
          'longitude': -122.09259560000001
        }
      ],
      'validTimeInterval': {
        'start': {
          'date': '2023-06-12T23:20:50.52Z'
        },
        'end': {
          'date': '2023-12-12T23:20:50.52Z'
        }
      }
    };

    data += '--batch_createobjectbatch\n';
    data += 'Content-Type: application/json\n\n';
    data += 'POST /walletobjects/v1/offerObject\n\n';

    data += JSON.stringify(batchObject) + '\n\n';
  }
  data += '--batch_createobjectbatch--';

  // Invoke the batch API calls
  let response = await this.client.context._options.auth.request({
    url: 'https://walletobjects.googleapis.com/batch',
    method: 'POST',
    data: data,
    headers: {
      // `boundary` is the delimiter between API calls in the batch request
      'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch'
    }
  });

  console.log('Batch insert response');
  console.log(response);
}

Go

หากต้องการเริ่มการผสานรวมใน Go ให้ดูตัวอย่างโค้ดทั้งหมดใน GitHub ตัวอย่างโค้ดใน GitHub

// Batch create Google Wallet objects from an existing class.
func (d *demoOffer) batchCreateObjects(issuerId, classSuffix string) {
	data := ""
	for i := 0; i < 3; i++ {
		objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")

		offerObject := new(walletobjects.OfferObject)
		offerObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
		offerObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
		offerObject.State = "ACTIVE"

		offerJson, _ := json.Marshal(offerObject)
		batchObject := fmt.Sprintf("%s", offerJson)

		data += "--batch_createobjectbatch\n"
		data += "Content-Type: application/json\n\n"
		data += "POST /walletobjects/v1/offerObject\n\n"
		data += batchObject + "\n\n"
	}
	data += "--batch_createobjectbatch--"

	res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))

	if err != nil {
		fmt.Println(err)
	} else {
		b, _ := io.ReadAll(res.Body)
		fmt.Printf("Batch insert response:\n%s\n", b)
	}
}