クライアント ライブラリを構築する

Google APIs Discovery Service を使用すると、Google API で使用するさまざまなツールを構築できます。ただし、ディスカバリ ドキュメントの主な目的は、Google がさまざまなプログラミング言語でクライアント ライブラリを作成できるようにすることです。このドキュメントでは、Google API にカスタム クライアント ライブラリを作成する方法について説明します。

安定していて機能が完全なクライアント ライブラリは複雑なツールで、開発に数か月かかります。ただし、Google API のシンプルなクライアント ライブラリを構築するための手順は、次の 3 つの簡単なステップにまとめることができます。

  1. ディスカバリ ドキュメントを取得して API サーフェスを構築する
  2. リクエストを作成する
  3. 呼び出しを行ってレスポンスを取得する

手順については、以降のセクションで詳しく説明します。また、「例」セクションのシンプルな API クライアントのサンプルでは、これらの手順とコードがどのように対応しているかを確認することもできます。

ディスカバリ ドキュメントを取得する

クライアント ライブラリの実装を開始する前に、開発過程に影響する基本的な要件がいくつかあります。たとえば、使用するプログラミング言語は型付きのものと、型なしのものがあります。また、型付けを動的に行うものも、静的に行うものもあります。コンパイルまたは解釈が必要な場合もあります。これらの要件により、ディスカバリ ドキュメントの使用方法が決まります。

最初の開発タスクは、ディスカバリ ドキュメントの取得です。ドキュメントを取得する正確なタイミングに関する戦略は、特定した要件によって決まります。たとえば、静的型言語では、プロセスの早い段階でディスカバリ ドキュメントを取得し、そのドキュメントに記述されている特定の API の処理コードを生成します。厳密な型付けを行う言語の場合は、コードを生成し、コンパイル済みのライブラリを構築します。動的型言語の場合、プログラミング構造の構築を遅らせて、プログラミング サーフェスが使用されるときに API とのインターフェースを構築できます。

リクエストを作成する

リクエストの作成には次の 2 つのステップがあります。

  1. リクエスト本文を作成する。
  2. リクエスト URL を作成する。

リクエスト本文がある場合は、言語に適した表現を正しい作成形式に変換する必要があります。たとえば、Java クライアント ライブラリでは、リクエスト データの型安全性操作を許可し、JSON にシリアル化可能なリクエスト タイプごとにクラスが存在する場合があります。

リクエスト URL の構成はやや複雑なプロセスです。

API の各メソッドの path プロパティでは、URI テンプレート v04 構文を使用します。このプロパティには、中かっこで囲まれた変数を含めることができます。変数を含む path プロパティの例を次に示します。

/example/path/var

上記のパスでは、var が変数です。この変数の値は、そのメソッドのディスカバリ ドキュメントの parameters セクションから取得されます。各変数名には、parameters オブジェクトに対応する値があります。上記の例では、var という名前のパラメータが parameters セクションにあります(この location プロパティは path で、これがパス変数であることを示します)。

リクエストを行う際は、var の値を URL に置き換える必要があります。たとえば、ライブラリのユーザーが var を値 foo に設定した場合、新しい URL は /example/path/foo になります。

また、path プロパティは相対 URI です。絶対 URI を計算する手順は次のとおりです。

  1. ロケーション(リージョン)がわかっていて、ディスカバリ ドキュメントに endpoints プロパティがある場合は、ロケーションが endpoints リストに含まれているかどうかを確認します。その場合は、location が自身のものと一致する endpoints リストから endpointUrl を取得します。
  2. ディスカバリ ドキュメントに endpoints プロパティがない場合、ロケーションが endpoints リストにない場合、またはグローバル エンドポイントをターゲットにする場合は、最上位のディスカバリ ドキュメントから rootUrl プロパティを取得します。

    たとえば、Service Usage APIディスカバリ ドキュメントrootUrl プロパティは次のとおりです。

    https://serviceusage.googleapis.com/
  3. ディスカバリ ドキュメントの最上位から servicePath を取得します。たとえば、Service Usage API のディスカバリ ドキュメントの servicePath プロパティは空です。
  4. これらを連結すると、次のようになります。

    https://serviceusage.googleapis.com/
  5. path プロパティを取得し、URI テンプレートとして展開して、その結果を前のステップの URI と結合します。たとえば、v1 Service Usage API の serviceusage.services.enable メソッドでは、path プロパティの値は v1/{+name}:enable です。したがって、このメソッドの完全な URI は次のようになります。

    https://serviceusage.googleapis.com/v1/{+name}:enable

Service Usage API の呼び出しに API キーは必要ありません。ただし、呼び出す API で API キーが必要な場合は、URI のクエリ文字列にその API キーを追加できます。

REQUEST_URI?key=API_KEY

呼び出しを行い、レスポンスを処理する

リクエストを送信した後、レスポンスのシリアル化を解除して適切な言語表現に変換する必要があります。その際、発生する可能性のあるエラーの状態について、基盤となる HTTP トランスポートと API サービスから生成されたエラー メッセージの両方で確認してください。エラーの形式は、Google JSON スタイルガイドで説明されています。

次のセクションでは、API クライアント ライブラリの簡単な例を示します。

シンプルな API クライアント

Python3 で記述された非常にシンプルなクライアント ライブラリの例を次に示します。クライアントは、Service Usage API とやりとりするインターフェースを構築し、そのインターフェースを使用してプロジェクト my-project で Compute Engine API(compute.googleapis.com)を有効にします。

import httplib2
import json
import uritemplate
import urllib

# Step 1: Fetch Discovery document
DISCOVERY_URI = "https://serviceusage.googleapis.com/$discovery/rest?version=v1"
h = httplib2.Http()
resp, content = h.request(DISCOVERY_URI)
discovery = json.loads(content)
location = None # Set this to your location if appropriate
use_global_endpoint = True # Set this to False if you want to target the endpoint for your location

# Step 2.a: Construct base URI
BASE_URL = None
if not use_global_endpoint and location:
  if discovery['endpoints']:
    BASE_URL = next((item['endpointUrl'] for item in discovery['endpoints'] if item['location'] == location), None)
if not BASE_URL:
  BASE_URL = discovery['rootUrl']
BASE_URL += discovery['servicePath']

class Collection(object): pass

def createNewMethod(name, method):
  # Step 2.b Compose request
  def newMethod(**kwargs):
    body = kwargs.pop('body', None)
    url = urllib.parse.urljoin(BASE_URL, uritemplate.expand(method['path'], kwargs))
    for pname, pconfig in method.get('parameters', {}).items():
      if pconfig['location'] == 'path' and pname in kwargs:
        del kwargs[pname]
    if kwargs:
      url = url + '?' + urllib.parse.urlencode(kwargs)
    return h.request(url, method=method['httpMethod'], body=body,
                     headers={'content-type': 'application/json'})

  return newMethod

# Step 3.a: Build client surface
def build(discovery, collection):
  for name, resource in discovery.get('resources', {}).items():
    setattr(collection, name, build(resource, Collection()))
  for name, method in discovery.get('methods', {}).items():
    setattr(collection, name, createNewMethod(name, method))
  return collection

# Step 3.b: Use the client
service = build(discovery, Collection())
print (serviceusage.services.enable(name='projects/my-project/services/compute.googleapis.com'))

クライアントの重要なコンポーネントは次のとおりです。

  • ステップ 1: ディスカバリ ドキュメントを取得する。Service Usage API のディスカバリ ドキュメントが取得され、解析されてデータ構造に変換されます。Python は動的型付き言語であるため、ディスカバリ ドキュメントの実行時に取得できます。
  • ステップ 2.a: ベース URI を作成する。ベース URI が計算されます。
  • ステップ 2.b: リクエストを作成する。コレクションでメソッドが呼び出されると、メソッドに渡されたパラメータを使用して URI テンプレートが展開され、ロケーション(query)を含むパラメータが URL のクエリ パラメータに挿入されます。最後に、ディスカバリ ドキュメントで指定された HTTP メソッドを使用して、作成された URL にリクエストが送信されます。
  • ステップ 3.a: クライアント サーフェスを構築する。クライアント サーフェスは、解析されたディスカバリ ドキュメントで再帰的に降順で構築されます。methods セクションのメソッドごとに、新しいメソッドが Collection オブジェクトに関連付けられます。コレクションはネストできるため、resources を探し、見つかった場合はすべてのメンバーの Collection オブジェクトを再帰的に作成します。ネストされた各コレクションは、Collection オブジェクトの属性としても関連付けられます。
  • ステップ 3.b: クライアントを使用する。構築された API サーフェスがどのように使用されるかを示します。まず、ディスカバリ ドキュメントからサービス オブジェクトが構築され、次に Service Usage API を使用してプロジェクト my-project で Compute Engine API が有効になります。