نصائح بشأن الأداء

ويتناول هذا المستند بعض الأساليب التي يمكنك استخدامها لتحسين أداء تطبيقك. في بعض الحالات، يتم استخدام أمثلة من واجهات برمجة تطبيقات أخرى أو واجهات برمجة تطبيقات عامة لتوضيح الأفكار المعروضة. ومع ذلك، تنطبق المفاهيم نفسها على Google Wallet API.

الضغط باستخدام gzip

وهناك طريقة سهلة وملائمة لتقليل معدل نقل البيانات اللازم لكل طلب، وهي تمكين الضغط بتنسيق gzip. وعلى الرغم من أن هذا يتطلب وقتًا إضافيًا لوحدة المعالجة المركزية (CPU) لفك ضغط النتائج، فإن المقايضة مع تكاليف الشبكة عادةً ما تجعل الأمر مفيدًا للغاية.

لتلقي استجابة بترميز gzip، عليك عمل شيئين: ضبط العنوان Accept-Encoding وتعديل وكيل المستخدم بحيث يتضمن السلسلة gzip. في ما يلي مثال على عناوين HTTP تم تشكيلها بشكل صحيح لتفعيل ضغط gzip:

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

استخدام الموارد الجزئية

هناك طريقة أخرى لتحسين أداء طلبات البيانات من واجهة برمجة التطبيقات، وهي إرسال واستلام جزء البيانات الذي يهمّك فقط. ويتيح ذلك لتطبيقك تجنب نقل الحقول غير الضرورية وتحليلها وتخزينها، حتى يتمكن من استخدام الموارد بشكل أكثر فعالية، بما في ذلك الشبكة ووحدة المعالجة المركزية (CPU) والذاكرة.

هناك نوعان من الطلبات الجزئية:

  • الردّ الجزئي: طلب يمكنك من خلاله تحديد الحقول المطلوب تضمينها في الردّ (استخدِم مَعلمة الطلب fields).
  • رمز التصحيح: طلب تعديل يمكنك من خلاله إرسال الحقول التي تريد تغييرها فقط (استخدِم فعل HTTP PATCH).

يتوفّر مزيد من التفاصيل حول إرسال طلبات جزئية في الأقسام التالية.

ردّ جزئي

يرسل الخادم تلقائيًا التمثيل الكامل للمورد بعد معالجة الطلبات. للحصول على أداء أفضل، يمكنك أن تطلب من الخادم إرسال الحقول التي تحتاجها فقط والحصول على ردّ جزئي بدلاً من ذلك.

لطلب استجابة جزئية، استخدِم مَعلمة طلب fields لتحديد الحقول التي تريد عرضها. يمكنك استخدام هذه المعلمة مع أي طلب يعرض بيانات الاستجابة.

يُرجى العِلم أنّ مَعلمة fields تؤثر فقط في بيانات الردّ. فلن يؤثر ذلك على البيانات التي تحتاج إلى إرسالها، إن وجدت. لتقليل كمية البيانات التي ترسلها عند تعديل الموارد، استخدِم طلب تصحيح.

مثال

يوضح المثال التالي استخدام المعلمة fields مع عنصر تجريبي عام (خيالي) واجهة برمجة التطبيقات.

طلب بسيط: يحذف طلب 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.

    استثناء: لردود واجهة برمجة التطبيقات التي تستخدم "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"
    }
  },
  ...
  ]
}

ملاحظة: بالنسبة إلى واجهات برمجة التطبيقات التي تتيح استخدام مَعلمات طلب البحث لتقسيم البيانات على صفحات (على سبيل المثال، maxResults وnextPageToken)، يمكنك استخدام هذه المَعلمات لتقليل نتائج كل طلب بحث إلى حجم يمكن إدارته. وبخلاف ذلك، قد لا يتم تحقيق مكاسب الأداء الممكنة في حالة استجابة جزئية.

رمز التصحيح (تحديث جزئي)

يمكنك أيضًا تجنُّب إرسال بيانات غير ضرورية عند تعديل الموارد. لإرسال البيانات المعدّلة فقط للحقول المحدّدة التي تريد تغييرها، استخدِم فعل HTTP PATCH. تختلف دلالات رمز التصحيح الموضَّحة في هذا المستند (وأبسط) عن تلك التي كانت في ما يخص تنفيذ GData الأقدم والتحديث الجزئي.

يوضّح المثال القصير أدناه كيف يؤدي استخدام رمز التصحيح إلى تقليل البيانات التي تحتاج إلى إرسالها لإجراء تعديل بسيط.

مثال

يعرض هذا المثال طلب تصحيح بسيط لتحديث عنوان "نسخة تجريبية" عامة (خيالية) فقط مورد واجهة برمجة التطبيقات. يحتوي المورد أيضًا على تعليق ومجموعة من الخصائص والحالة والعديد من الحقول الأخرى، ولكن هذا الطلب يرسل فقط الحقل 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 فارغة.

ملاحظة بشأن الصفائف: تستبدل طلبات التصحيح التي تحتوي على صفائف المصفوفة الحالية بالمصفوفة التي تقدّمها. لا يمكنك تعديل عناصر أو إضافتها أو حذفها في مصفوفة بشكل مجزّأ.

استخدام رمز التصحيح في دورة القراءة والتعديل والكتابة

قد يكون من المفيد البدء باسترداد رد جزئي بالبيانات التي تريد تعديلها. ويُعدّ هذا الإجراء مهمًا على وجه الخصوص للموارد التي تستخدم علامات 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. */
  },
}

يستجيب الخادم برمز حالة OK HTTP 200، والتمثيل الجزئي للمورد الذي تم تحديثه:

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. */
  }
}

إنشاء طلب تصحيح مباشرةً

بالنسبة إلى بعض طلبات التصحيح، يجب أن تبني هذه الطلبات على البيانات التي استعدتها سابقًا. على سبيل المثال، إذا أردت إضافة عنصر إلى مصفوفة ولا تريد فقدان أي من عناصر الصفيف الموجودة، يجب عليك الحصول على البيانات الحالية أولاً. وبالمثل، إذا كانت واجهة برمجة التطبيقات تستخدم علامات 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
  }
}

مع هذا الطلب، إذا كان حقل التعليق يحتوي على قيمة حالية، ستحل القيمة الجديدة محلها؛ وإلا يتم تعيينها على القيمة الجديدة. وبالمثل، إذا كانت هناك خاصية حجم، يتم استبدال قيمتها؛ وإذا لم يكن كذلك، فسيتم إنشاؤه. وتتم إزالة حقل الدقة في حال ضبطه.

التعامل مع الرد على رمز التصحيح

بعد معالجة طلب تصحيح صالح، تعرض واجهة برمجة التطبيقات رمز استجابة HTTP 200 OK مع التمثيل الكامل للمورد المعدّل. في حال استخدام علامات ETag بواسطة واجهة برمجة التطبيقات، يعدِّل الخادم قيم ETag عند معالجة طلب تصحيح بنجاح، كما هو الحال مع PUT.

يعرض طلب التصحيح تمثيل المورد بالكامل ما لم تستخدم المعلمة fields لتقليل كمية البيانات التي يعرضها.

إذا نتج عن طلب التصحيح حالة مورد جديدة غير صالحة من ناحية البنية أو دلاليًا، يعرض الخادم رمز حالة HTTP 400 Bad Request أو 422 Unprocessable Entity وتبقى حالة المورد بدون تغيير. على سبيل المثال، إذا حاولت حذف قيمة حقل مطلوب، سيعرض الخادم خطأ.

التدوين البديل عندما لا يكون فعل PATCH HTTP متاحًا

إذا كان جدار الحماية لا يسمح بطلبات HTTP PATCH، يمكنك تنفيذ طلب HTTP POST وضبط عنوان الإلغاء على PATCH، كما هو موضّح أدناه:

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

الفرق بين رمز التصحيح والتحديث

من الناحية العملية، عند إرسال بيانات لطلب تعديل يستخدم فعل HTTP PUT، يجب إرسال الحقول المطلوبة أو الاختيارية فقط. وفي حال إرسال قيم للحقول التي ضبطها الخادم، سيتم تجاهلها. على الرغم من أنّ هذه الطريقة قد تبدو طريقة أخرى لإجراء تعديل جزئي، فإنّ هذه الطريقة لها بعض القيود. مع التحديثات التي تستخدم فعل HTTP PUT، يتعذّر الطلب في حال عدم توفير المَعلمات المطلوبة، كما يمحو البيانات التي تم ضبطها سابقًا في حال عدم توفير مَعلمات اختيارية.

لهذا السبب، من الآمن استخدام رمز التصحيح. يمكنك توفير بيانات للحقول التي تريد تغييرها فقط، لن يتم محو الحقول التي حذفتها. يحدث الاستثناء الوحيد لهذه القاعدة مع العناصر أو الصفائف المتكررة: إذا حذفتها جميعًا، فستظل كما هي؛ في حال توفير أيٍّ منها، يتمّ استبدال المجموعة الكاملة بالمجموعة التي تقدّمها.

الطلبات المجمّعة إلى "محفظة Google"

تتيح Google Wallet API تجميع طلبات البيانات من واجهة برمجة التطبيقات معًا لتقليل عدد الطلبات الاتصالات التي يتعين على العميل إجراؤها. لمزيد من المعلومات حول الطلب المجمّع بنية الاستجابة، يُرجى الاطّلاع على تفاصيل المجموعة.

يوضح الرمز النموذجي التالي طلبات التجميع. لغة Java وPHP يمكنك مثلاً استخدام محفظة Google المكتبات لتبسيط إنشاء الفئات والكائنات.

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<LoyaltyObject> callback =
      new JsonBatchCallback<LoyaltyObject>() {
        // Invoked if the request was successful
        public void onSuccess(LoyaltyObject 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/loyalty-cards/rest/v1/loyaltyobject
    LoyaltyObject batchObject =
        new LoyaltyObject()
            .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)))
            .setAccountId("Account ID")
            .setAccountName("Account name")
            .setLoyaltyPoints(
                new LoyaltyPoints()
                    .setLabel("Points")
                    .setBalance(new LoyaltyPointsBalance().setInt(800)));

    service.loyaltyobject().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/loyalty-cards/rest/v1/loyaltyobject
    $batchObject = new LoyaltyObject([
      '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
        ])
      ],
      'accountId' => 'Account ID',
      'accountName' => 'Account name',
      'loyaltyPoints' => new LoyaltyPoints([
        'balance' => new LoyaltyPointsBalance([
          'int' => 800
        ])
      ])
    ]);

    $batch->add($this->service->loyaltyobject->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

لبدء عملية الدمج في بايثون، يُرجى الرجوع إلى عيّنات من الرموز البرمجية على 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/loyalty-cards/rest/v1/loyaltyobject
        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
            }],
            'accountId': 'Account id',
            'accountName': 'Account name',
            'loyaltyPoints': {
                'label': 'Points',
                'balance': {
                    'int': 800
                }
            }
        }

        batch.add(self.client.loyaltyobject().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/loyalty-cards/rest/v1/loyaltyobject
    LoyaltyObject batchObject = new LoyaltyObject
    {
      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
        }
      },
      AccountId = "Account id",
      AccountName = "Account name",
      LoyaltyPoints = new LoyaltyPoints
      {
        Label = "Points",
        Balance = new LoyaltyPointsBalance
        {
          Int__ = 800
        }
      }
    };

    data += "--batch_createobjectbatch\n";
    data += "Content-Type: application/json\n\n";
    data += "POST /walletobjects/v1/loyaltyObject/\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

لبدء عملية الدمج في Node، يُرجى الرجوع إلى عيّنات من الرموز البرمجية على 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/loyalty-cards/rest/v1/loyaltyobject
    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
        }
      ],
      'accountId': 'Account id',
      'accountName': 'Account name',
      'loyaltyPoints': {
        'label': 'Points',
        'balance': {
          'int': 800
        }
      }
    };

    data += '--batch_createobjectbatch\n';
    data += 'Content-Type: application/json\n\n';
    data += 'POST /walletobjects/v1/loyaltyObject\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، يُرجى الرجوع إلى العيّنات الكاملة من الرموز البرمجية على GitHub. عيّنات التعليمات البرمجية على GitHub.

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

		loyaltyObject := new(walletobjects.LoyaltyObject)
		loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
		loyaltyObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
		loyaltyObject.AccountName = "Account name"
		loyaltyObject.AccountId = "Account id"
		loyaltyObject.State = "ACTIVE"

		loyaltyJson, _ := json.Marshal(loyaltyObject)
		batchObject := fmt.Sprintf("%s", loyaltyJson)

		data += "--batch_createobjectbatch\n"
		data += "Content-Type: application/json\n\n"
		data += "POST /walletobjects/v1/loyaltyObject\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)
	}
}