Route Optimization API ウェブサービスの使用に関するベスト プラクティス

Google Maps Platform ウェブサービスは、地図アプリケーションに地理データを提供する Google サービスへの HTTP インターフェースのコレクションです。

このガイドでは、ウェブサービス リクエストの設定やサービス レスポンスの処理に役立つ一般的なプラクティスについて説明します。Route Optimization API の詳細なドキュメントについては、デベロッパー ガイドをご覧ください。

ウェブサービスとは

Google Maps Platform ウェブサービスは、外部サービスに Maps API のデータをリクエストし、マップ アプリケーション内でそのデータを使用するためのインターフェースです。これらのサービスは、Google Maps Platform 利用規約のライセンス制限に基づき、地図と組み合わせて使用するように設計されています。

Maps API のウェブサービスは、特定の URL に対して HTTP(S) リクエストを使用し、URL パラメータや JSON 形式の POST データを引数としてサービスに渡します。通常、これらのサービスは、アプリケーションで解析や処理を行うために、レスポンス本文でデータを JSON として返します。

次の例は、optimizeTours メソッドに対する REST POST リクエストの URL を示しています。

https://routeoptimization.googleapis.com/v1/projects/PROJECT_NUMBER:optimizeTours

PROJECT_NUMBER は、Route Optimization API が有効になっている Cloud プロジェクトの番号または ID に置き換えます。

OptimizeToursRequest メッセージを JSON リクエスト本文として含めます。

: すべての Route Optimization API アプリケーションに認証が必要です。認証情報の詳細を確認する。

SSL/TLS アクセス

API キーを使用する、またはユーザーデータを含むすべての Google Maps Platform リクエストで HTTPS を使用する必要があります。機密データを含む HTTP 経由のリクエストは拒否されることがあります。

有効な URL の作成

「有効」な URL とは何か、説明の必要はないと考えられるかもしれませんが、それほど単純なことではありません。ブラウザのアドレスバーに入力される URL には特殊文字("上海+中國" など)が含まれている場合があります。このような特殊文字は、ブラウザで別のエンコードに内部的に変換してから送信する必要があります。同様に、UTF-8 入力を生成または受け付けるコードでは、UTF-8 の文字が使用された URL を「有効」な URL として扱うことがありますが、それらの文字はウェブサーバーに送信する前に変換する必要があります。このプロセスは、URL エンコードまたはパーセント エンコードと呼ばれます。

特殊文字

すべての URL は URI(Uniform Resource Identifier)仕様で規定されている構文に従う必要があるため、特殊文字を変換する必要があります。つまり、URL には、ASCII 文字の特別なサブセット(よく使用される英数記号および URL 内で制御文字として使用される予約文字)のみを含める必要があります。次の表は、こうした特殊記号をまとめたものです。

有効な URL 文字の概要
セット文字URL での使用法
英数字 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 テキスト文字列、スキームでの使用(http)、ポート(8080)など
未予約 - _ . ~ テキスト文字列
予約済み ! * ' ( ) ; : @ & = + $ , / ? % # [ ] 制御文字やテキスト文字列

有効な URL を作成するときは、有効な URL 文字の概要表に記載されている文字のみを使用する必要があります。しかし、URL での使用がこの文字セットだけに制限された場合、通常は 2 つの問題が発生します。1 つは省略、もう 1 つは置き換えです。

  • 処理する文字が上記のセットに含まれない場合。たとえば、「上海+中國」のような英語以外の文字は、上記の文字を使用してエンコードする必要があります。一般的な命名規則では、URL 内で使用できないスペースもプラス記号 '+' を使用して表します。
  • 上記のセットに予約文字として含まれる文字を、リテラル文字として使用する必要がある場合。たとえば、「?」は URL 内でクエリ文字列の先頭を示すために使用されます。文字列「? and the Mysterions」を使用する場合は、文字 '?' をエンコードする必要があります。

URL エンコードが必要なすべての文字を、'%' と、UTF-8 文字に対応する 2 文字の 16 進数値を使用してエンコードします。たとえば、UTF-8 の「上海+中國」は、「%E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B」として URL エンコードされます。文字列「? and the Mysterians」は、「%3F+and+the+Mysterians」または「%3F%20and%20the%20Mysterians」として URL エンコードされます。

エンコードが必要な一般的な文字

エンコードする必要がある一般的な文字は次のとおりです。

危険な文字 エンコードされた値
Space %20
%22
< %3C
> %3E
# %23
% %25
| %7C

ユーザー入力から受け取った URL の変換には、場合によって注意が必要です。たとえば、ユーザーが住所を「5th&Main St.」と入力することも考えられます。通常は、ユーザー入力をリテラル文字として処理して、URL をパーツから作成する必要があります。

さらに、URL は、すべての Google Maps Platform ウェブサービスと Static Web API で 16,384 文字に制限されています。ほとんどのサービスでは、この文字制限に達することはめったにありません。ただし、複数のパラメータを持つ特定のサービスでは、URL が長くなる可能性があります。

Google API の適切な使用

API クライアントの設計に問題があると、インターネットと Google のサーバーの両方に必要以上の負荷がかかる可能性があります。このセクションでは、API のクライアントのベスト プラクティスについて説明します。以下のベスト プラクティスに従うことで、API の意図しない不正使用によってアプリケーションがブロックされないようにすることができます。

指数関数的バックオフ

まれに、リクエストの処理で問題が発生する場合があります。4XX または 5XX HTTP レスポンス コードが返される場合や、クライアントと Google のサーバー間のどこかで TCP 接続が失敗する場合もあります。元のリクエストが失敗したときにフォローアップ リクエストが成功する場合があるため、リクエストを再試行することをおすすめします。ただし、Google のサーバーへのリクエストを繰り返しループさせるだけではないことが重要です。このループ動作は、クライアントと Google 間のネットワークに過負荷をかけ、多くの当事者に問題を引き起こす可能性があります。

より適切な方法は、試行間の遅延を増加させながら再試行することです。通常、遅延は試行のたびに乗法係数によって増加します。これは指数バックオフとして知られるアプローチです。

たとえば、Time Zone API に次のリクエストを送信するアプリケーションを考えてみましょう。

https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=1331161200&key=YOUR_API_KEY

次の Python の例では、指数関数的バックオフを使用してリクエストを実行する方法を示しています。

import json
import time
import urllib.error
import urllib.parse
import urllib.request

# The maps_key defined below isn't a valid Google Maps API key.
# You need to get your own API key.
# See https://developers.google.com/maps/documentation/timezone/get-api-key
API_KEY = "YOUR_KEY_HERE"
TIMEZONE_BASE_URL = "https://maps.googleapis.com/maps/api/timezone/json"


def timezone(lat, lng, timestamp):

    # Join the parts of the URL together into one string.
    params = urllib.parse.urlencode(
        {"location": f"{lat},{lng}", "timestamp": timestamp, "key": API_KEY,}
    )
    url = f"{TIMEZONE_BASE_URL}?{params}"

    current_delay = 0.1  # Set the initial retry delay to 100ms.
    max_delay = 5  # Set the maximum retry delay to 5 seconds.

    while True:
        try:
            # Get the API response.
            response = urllib.request.urlopen(url)
        except urllib.error.URLError:
            pass  # Fall through to the retry loop.
        else:
            # If we didn't get an IOError then parse the result.
            result = json.load(response)

            if result["status"] == "OK":
                return result["timeZoneId"]
            elif result["status"] != "UNKNOWN_ERROR":
                # Many API errors cannot be fixed by a retry, e.g. INVALID_REQUEST or
                # ZERO_RESULTS. There is no point retrying these requests.
                raise Exception(result["error_message"])

        if current_delay > max_delay:
            raise Exception("Too many retry attempts.")

        print("Waiting", current_delay, "seconds before retrying.")

        time.sleep(current_delay)
        current_delay *= 2  # Increase the delay each time we retry.


if __name__ == "__main__":
    tz = timezone(39.6034810, -119.6822510, 1331161200)
    print(f"Timezone: {tz}")

また、アプリケーション呼び出しチェーンの上位に再試行コードがないので、リクエストが連続して繰り返されないように注意する必要があります。

同期されたリクエスト

Google の API への大量の同期されたリクエストは、Google のインフラストラクチャに対する分散型サービス拒否(DDoS)攻撃のように見え、適切に扱われる可能性があります。これを回避するには、クライアント間で API リクエストが同期されないようにする必要があります。

たとえば、現在のタイムゾーンで時刻を表示するアプリケーションについて考えてみましょう。このアプリケーションは、表示時刻を更新できるように、毎分 0 秒に起動するクライアント オペレーティング システムでアラームを設定します。アプリケーションは、そのアラームに関連する処理の一部として API 呼び出しを行わないでください。

固定アラームに応じて API 呼び出しを行うと、API 呼び出しが時間の経過とともに均等に分散されず、異なるデバイス間でも毎分 0 秒に同期されるため、不適切です。このように設計が不十分なアプリケーションでは、1 分ごとに通常の 60 倍のレベルでトラフィックが急増します。

代わりに、ランダムに選択された時刻に 2 つ目のアラームを設定することをおすすめします。この 2 回目のアラームが発生すると、アプリは必要な API を呼び出し、結果を保存します。毎分 0 時に表示を更新する場合、API を再度呼び出すのではなく、以前に保存された結果を使用します。このアプローチでは API 呼び出しが 時間の経過とともに均等に分散されますさらに、ディスプレイの更新時に API 呼び出しによってレンダリングが遅延することはありません。

毎正時以外の同期時刻については、毎正時と午前 0 時をターゲットとしないでください。

レスポンスの処理

このセクションでは、これらの値をウェブサービス レスポンスから動的に抽出する方法について説明します。

Google マップ ウェブサービスで提供されるレスポンスはわかりやすいものですが、ユーザー フレンドリーとは言えません。クエリを実行するときは、データセットを表示するのではなく、特定の値をいくつか抽出することをおすすめします。一般に、ウェブサービスからのレスポンスを解析し、必要な値のみを抽出します。

使用する解析スキームは、JSON で出力を返すかどうかによって異なります。すでに JavaScript オブジェクトの形式になっている JSON レスポンスは、クライアントの JavaScript 内で処理できます。