성능 팁

이 문서에서는 애플리케이션의 성능을 개선할 수 있는 몇 가지 기술에 대해 설명합니다. 경우에 따라 개념을 설명하기 위해 다른 API 또는 일반적인 API의 예가 사용되기도 하지만, 같은 개념이 Google Wallet API에도 적용됩니다.

gzip을 사용한 압축

각 요청에 필요한 대역폭을 줄이는 쉽고 편리한 한 가지 방법은 gzip 압축을 사용하는 것입니다. 이 경우 결과를 압축 해제하려면 CPU 시간이 추가로 필요하기는 하지만 대신에 네트워크 비용을 절감할 수 있다는 장점이 있습니다.

gzip으로 인코딩된 응답을 받으려면 Accept-Encoding 헤더를 설정하고 사용자 에이전트에 gzip 문자열이 포함되도록 수정해야 합니다. 다음은 gzip 압축을 사용할 수 있도록 적절하게 구성된 HTTP 헤더의 예시입니다.

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

부분 리소스 작업

API 호출의 성능을 개선하는 또 다른 방법은 관심 있는 데이터 부분만 보내고 받는 것입니다. 이렇게 하면 애플리케이션에서 불필요한 필드를 전송하고 파싱하고 저장하지 않게 되므로 네트워크, CPU, 메모리를 포함한 리소스를 더 효율적으로 사용할 수 있습니다.

다음과 같은 두 가지 유형의 부분 요청이 있습니다.

  • 부분 응답: 응답에 포함할 필드를 지정하는 요청(fields 요청 매개변수 사용)
  • 패치: 변경할 필드만 전송하는 업데이트 요청(PATCH HTTP 동사 사용)

부분 요청을 작성하는 자세한 방법은 다음 섹션에 설명되어 있습니다.

부분 응답

기본적으로 서버에서는 요청을 처리한 후에 전체 리소스 표현을 반환합니다. 더 나은 성능을 위해 서버에 필요한 필드만 전송하도록 요청하여 부분 응답을 받을 수 있습니다.

부분 응답을 요청하려면 fields 요청 매개변수를 사용하여 반환받을 필드를 지정합니다. 응답 데이터를 반환하는 모든 요청에서 이 매개변수를 사용할 수 있습니다.

fields 매개변수는 응답 데이터에만 영향을 주며 전송해야 하는 데이터에는 영향을 주지 않습니다. 리소스를 수정할 때 전송하는 데이터의 양을 줄이려면 패치 요청을 사용하세요.

다음 예시에서는 일반적인(가상의) 'Demo' API에 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)

부분 응답: 위 요청에 대해 서버에서 반환하는 응답에는 종류(kind) 정보와 짧게 줄인 항목(items) 배열만 포함되며, 이 항목 배열에는 각 항목의 HTML 제목 및 길이 특성 정보만 포함됩니다.

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

이 응답은 선택한 필드와 해당 필드가 속한 상위 객체만 포함하는 JSON 객체입니다.

fields 매개변수의 형식을 지정하는 자세한 방법은 다음 부분에서 다루고 있으며, 그 다음 부분에는 응답에서 정확히 무엇이 반환되는지에 대해 자세히 설명되어 있습니다.

fields 매개변수 구문 요약

fields 요청 매개변수의 값 형식은 대략 XPath 구문을 기반으로 합니다. 지원되는 구문은 아래에 요약되어 있으며 이어지는 섹션에서 추가적인 예시를 확인할 수 있습니다.

  • 여러 필드를 선택하려면 쉼표로 구분된 목록을 사용합니다.
  • a 필드 내에 중첩된 b 필드를 선택하려면 a/b를 사용하고, b 내에 중첩된 c 필드를 선택하려면 a/b/c를 사용합니다.

    예외: data: { ... }와 같이 응답이 data 객체 내에 중첩되도록 'data' 래퍼를 사용하는 API 응답의 경우 fields 사양에 'data'를 포함하지 마세요. 필드를 지정할 때 data/a/b와 같이 data 객체를 포함하면 오류가 발생합니다. 대신 fieldsa/b와 같이 지정하세요.

  • 배열 또는 객체의 특정 하위 필드 세트를 요청하려면 하위 선택자를 사용하여 표현식을 괄호 '( )'로 묶습니다.

    예: fields=items(id,author/email)는 items 배열에 포함된 각 요소의 항목 ID와 작성자 이메일만 반환합니다. 하위 필드를 하나만 지정할 수도 있으며, 이때 fields=items(id)fields=items/id와 같습니다.

  • 필요한 경우 필드 선택 구문에 와일드 카드를 사용합니다.

    예: fields=items/pagemap/*는 페이지 지도 내의 모든 객체를 선택합니다.

fields 매개변수 사용 방법의 추가 예시

아래 예시에서는 fields 매개변수 값이 응답에 미치는 영향을 설명합니다.

참고: 모든 쿼리 매개변수 값과 마찬가지로 fields 매개변수 값도 URL로 인코딩되어야 합니다. 이 문서의 예시에는 보기 쉽도록 인코딩이 생략되어 있습니다.

반환받을 필드 지정(또는 필드 선택)
fields 요청 매개변수 값은 쉼표로 구분된 필드 목록이며 각 필드는 응답의 루트를 기준으로 지정됩니다. 따라서 list 작업을 수행하는 경우에는 응답으로 컬렉션이 반환되며, 일반적으로 이 응답에는 리소스 배열이 포함됩니다. 하나의 리소스를 반환하는 작업을 수행하는 경우에는 리소스를 기준으로 필드가 지정됩니다. 선택한 필드가 배열(또는 배열의 일부)인 경우 서버에서는 배열의 모든 요소 중에서 선택된 부분을 반환합니다.

다음은 컬렉션 수준의 몇 가지 예시입니다.
예시 결과
items items 배열의 모든 요소를 반환하며 각 요소의 모든 필드가 포함되지만 다른 필드는 제외됩니다.
etag,items etag 필드 및 items 배열의 모든 요소를 반환합니다.
items/title items 배열에 포함된 모든 요소의 title 필드만 반환합니다.

중첩 필드가 반환되는 경우 응답에는 항상 해당 필드가 속한 상위 객체가 포함됩니다. 명시적으로 함께 선택하지 않은 다른 하위 필드는 상위 필드에 포함되지 않습니다.
context/facets/label context 객체 아래에 중첩된 facets 배열의 모든 구성원에 대해 label 필드만 반환합니다.
items/pagemap/*/title items 배열의 각 요소에 대해 pagemap의 하위 항목인 모든 객체의 title 필드(있는 경우)만 반환합니다.

다음은 리소스 수준의 몇 가지 예시입니다.
예시 결과
title 요청된 리소스의 title 필드를 반환합니다.
author/uri 요청된 리소스에서 author 객체의 uri 하위 필드를 반환합니다.
links/*/href
links의 하위 요소인 모든 객체의 href 필드를 반환합니다.
하위 선택을 사용하여 특정 필드의 일부만 요청
기본적으로 요청에서 특정 필드를 지정하면 서버에서는 해당하는 객체 또는 배열 요소 전체를 반환합니다. 하지만 특정 하위 필드만 포함하는 응답을 지정할 수도 있습니다. 아래 예시와 같이 '( )' 하위 선택 구문을 사용하면 됩니다.
예시 결과
items(title,author/uri) items 배열에 포함된 각 요소에 대해 title 및 author의 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"
    }
  },
  ...
  ]
}

참고: 데이터 페이지 나누기를 위한 쿼리 매개변수(예: maxResultsnextPageToken)를 지원하는 API의 경우 이러한 매개변수를 사용하여 각 쿼리의 결과를 관리 가능한 크기로 줄이세요. 그러지 않으면 부분 응답을 사용해도 성능이 개선되지 않을 수 있습니다.

패치(부분 업데이트)

리소스를 수정할 때 불필요한 데이터가 전송되지 않도록 할 수도 있습니다. 변경하려는 특정 필드의 업데이트된 데이터만 전송하려면 HTTP PATCH 동사를 사용합니다. 이 문서에 설명된 패치 시맨틱스는 이전에 부분 업데이트를 위해 구현되었던 GData 구문과는 다르며 더 간단해졌습니다.

아래의 짧은 예에서는 일부 데이터만 업데이트할 경우 패치를 사용하면 전송해야 하는 데이터가 얼마나 최소화되는지를 보여 줍니다.

이 예시에서는 일반적인(가상의) 'Demo' API 리소스의 제목만 업데이트하기 위한 간단한 패치 요청을 보여 줍니다. 이 리소스에는 comment, characteristics 세트, status 외 여러 필드가 있지만 이 요청은 title 필드만 전송합니다. 수정되는 유일한 필드이기 때문입니다.

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

{
  "title": "New title"
}

응답:

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

서버에서는 200 OK 상태 코드와 함께 업데이트된 리소스의 전체 표현을 반환합니다. title 필드만 패치 요청에 포함되었기 때문에 이 필드 값만 이전과 다릅니다.

참고: 부분 응답 fields 매개변수를 패치와 함께 사용하면 업데이트 요청의 효율을 훨씬 더 높일 수 있습니다. 패치 요청은 요청의 크기만을 줄입니다. 부분 응답은 응답의 크기를 줄입니다. 따라서 양방향으로 전송되는 데이터의 양을 줄이려면 패치 요청과 fields 매개변수를 함께 사용합니다.

패치 요청 구문

패치 요청의 본문에는 수정하려는 리소스 필드만 포함합니다. 부분 응답에서 필드가 속한 상위 항목이 반환되는 것과 마찬가지로, 요청에서 필드를 지정할 때도 해당 필드가 속한 모든 상위 객체를 포함해야 합니다. 수정된 데이터를 전송하면 해당 데이터가 상위 객체의 데이터에 병합됩니다.

  • 추가: 기존에 없던 필드를 추가하려면 새 필드와 해당 값을 지정합니다.
  • 수정: 기존 필드의 값을 변경하려면 필드를 지정하고 새로운 값으로 설정합니다.
  • 삭제: 필드를 삭제하려면 필드를 지정하고 null로 설정합니다. 예를 들면 "comment": null입니다. 또한 전체 객체(변경 가능한 경우)를 null로 설정하여 삭제할 수도 있습니다. Java API 클라이언트 라이브러리를 사용 중인 경우 Data.NULL_STRING을 대신 사용하세요. 자세한 내용은 JSON null을 참조하세요.

배열 참고사항: 배열이 포함된 패치 요청은 기존 배열을 사용자가 제공하는 배열로 바꿉니다. 배열의 항목을 부분적으로 수정하거나 추가하거나 삭제할 수는 없습니다.

읽기-수정-쓰기 주기로 패치 사용

먼저 수정하려는 데이터를 포함하는 부분 응답을 가져오는 것이 유용한 경우도 있습니다. ETag를 사용하는 리소스의 경우 If-Match HTTP 헤더에 현재 ETag를 제공해야 올바르게 업데이트되므로 이 방법이 특히 중요합니다. 데이터를 구한 후, 변경하고자 하는 값을 수정할 수 있으며, 패치 요청과 함께 수정된 부분에 대한 표시를 반송할 수 있습니다. 다음은 데모 리소스가 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. */
  },
}

서버에서는 200 OK HTTP 상태 코드와 함께 업데이트된 리소스의 부분 표현을 반환합니다.

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 값을 전송해야 합니다.

참고: ETag를 사용 중인 경우 "If-Match: *" HTTP 헤더를 사용하여 패치가 처리되도록 할 수 있습니다.  이렇게 하면 쓰기 전에 읽기를 수행하지 않아도 됩니다.

하지만 그 외의 경우에는 기존 데이터를 먼저 가져오지 않고 패치 요청을 직접 작성할 수 있습니다. 예를 들어 필드를 새로운 값으로 업데이트하거나 새 필드를 추가하는 패치 요청을 간편하게 설정할 수 있습니다. 예를 들면 다음과 같습니다.

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
  }
}

이 요청을 실행할 경우 comment 필드에 기존 값이 있으면 새로운 값이 기존 값을 덮어쓰고, 그렇지 않으면 comment 필드가 새로운 값으로 설정됩니다. 마찬가지로 볼륨(volume) 특성이 있으면 해당 값이 덮어써지고, 그렇지 않으면 새로 생성됩니다. 또한 accuracy 필드는 설정된 경우 제거됩니다.

패치에 대한 응답 처리

API는 올바른 패치 요청을 처리한 후 200 OK HTTP 응답 코드와 함께 수정된 리소스의 전체 표현을 반환합니다. API에 ETag가 사용되는 경우에는 PUT을 사용할 때와 마찬가지로 패치 요청이 성공적으로 처리되면 서버에서 ETag 값을 업데이트합니다.

fields 매개변수를 사용하여 반환되는 데이터의 양을 줄이지 않으면 패치 요청에서 전체 리소스 표현을 반환합니다.

패치 요청으로 인해 새로운 리소스 상태의 구문 또는 의미 체계가 올바르지 않게 되면 서버에서 400 Bad Request 또는 422 Unprocessable Entity HTTP 상태 코드를 반환하며 리소스 상태는 변경되지 않은 채 유지됩니다. 예를 들어 필수 필드의 값을 삭제하려고 하면 서버에서 오류가 반환됩니다.

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는 API 호출 일괄 처리를 지원하여 많은 수의 연결을 구성합니다. 일괄 요청 및 일괄 처리 작업에 대한 자세한 내용은 일괄 세부정보를 참고하세요.

다음 샘플 코드는 요청을 일괄 처리하는 방법을 보여줍니다. Java 및 PHP Google 월렛 라이브러리를 사용하여 클래스 및 객체 생성을 간소화합니다.

자바

Java에서 통합을 시작하려면 전체 <ph type="x-smartling-placeholder"></ph> 코드 샘플을 확인하세요.

/**
 * 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에서 통합을 시작하려면 전체 <ph type="x-smartling-placeholder"></ph> 코드 샘플을 확인하세요.

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

Python에서 통합을 시작하려면 전체 <ph type="x-smartling-placeholder"></ph> 코드 샘플을 확인하세요.

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#에서 통합을 시작하려면 전체 <ph type="x-smartling-placeholder"></ph> 코드 샘플을 확인하세요.

/// <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

노드에서 통합을 시작하려면 전체 <ph type="x-smartling-placeholder"></ph> 코드 샘플을 확인하세요.

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

Go에서 통합을 시작하려면 GitHub의 전체 코드 샘플을 참고하세요. <ph type="x-smartling-placeholder"></ph> 코드 샘플을 확인하세요.

// 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)
	}
}