ストリートビュー Static API のベスト プラクティス

Google Maps Platform の静的ウェブ API は、HTTP インターフェースのコレクションであり、ウェブページに直接埋め込む画像を生成します。

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

このガイドでは、画像とウェブサービスのリクエストの設定、およびサービス レスポンスの処理に役立つ一般的な方法について説明します。Street View Static API の詳細については、デベロッパー ガイドをご覧ください。

ストリートビュー Static API は静的ウェブ API のように動作し、メタデータ サービスはウェブサービスとして動作します。メタデータ サービスの詳細については、ストリートビューの画像のメタデータをご覧ください。

静的ウェブ API とは

Google Maps Platform の静的ウェブ API を使用すると、JavaScript や動的なページ読み込みを必要とせずに、Google マップの画像をウェブページに埋め込むことができます。静的ウェブ API は、標準の HTTPS リクエストを使用して送信される URL パラメータに基づいて画像を作成します。

一般的なストリートビュー Static API リクエストの形式は次のとおりです。

  https://www.googleapis.com/streetview/z/x/y?parameters

ウェブサービスとは

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

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

ストリートビュー Static API メタデータ リクエストの形式は次のとおりです。

https://maps.googleapis.com/maps/api/streetview/parameters

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 での使用がこの文字セットだけに制限された場合、通常は 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 エンコードされます。

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

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

危険な文字 エンコードされた値
スペース %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 クライアントは、インターネットやサーバーに大きな負荷をかける可能性があります。このセクションでは、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 in the following code 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 the request didn't produce an IOError, parse the result.
            result = json.load(response)

            if result["status"] == "OK":
                return result["timeZoneId"]
            elif result["status"] != "UNKNOWN_ERROR":
                # Many API errors can't be fixed by a retry, such as
                # INVALID_REQUEST or ZERO_RESULTS. Don't retry 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 on each retry.


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

アプリケーションのコールチェーンの上位に、リクエストを立て続けに繰り返す再試行コードがないことを確認します。

同期リクエスト

Google の API に対する多数の同期リクエストは、Google のインフラストラクチャに対する分散型サービス拒否(DDoS)攻撃のように見えるため、それに応じて処理される可能性があります。この問題を回避するには、API リクエストがクライアント間で同期されないようにします。

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

固定アラームに応じて API 呼び出しを行うと、API 呼び出しが時間の経過とともに均等に分散されるのではなく、異なるデバイス間でも分の開始時に同期されるため、適切ではありません。このような処理を行うアプリケーションの設計が不十分な場合、毎分の開始時に通常の 60 倍のトラフィックの急増が発生します。

代わりに、ランダムに選択された時間に設定された 2 つ目のアラームを持つようにアプリを設計できます。この 2 番目のアラームが鳴ると、アプリは必要な API を呼び出して結果を保存します。アプリは、1 分の開始時に表示を更新するときに、API を再度呼び出すのではなく、以前に保存した結果を使用します。この方法では、API 呼び出しが時間とともに均等に分散されます。さらに、API 呼び出しによって、ディスプレイの更新時にレンダリングが遅れることはありません。

分の開始以外に、1 時間の開始や毎日の深夜 0 時の開始など、他の一般的な同期時間をターゲットにしないでください。

レスポンスの処理

ウェブサービス リクエストに対する個々のレスポンスの正確な形式は保証されていません。一部の要素が欠落している場合や、複数の場所にある場合があるため、特定のレスポンスに対して返される形式が、異なるクエリでも同じであるとは限りません。代わりに、レスポンスを処理し、式を使用して適切な値を選択します。

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

Google マップ ウェブサービスは、理解しやすいものの、ユーザー フレンドリーではないレスポンスを提供します。クエリを実行するときに、一連のデータを表示するのではなく、特定の値をいくつか抽出したい場合があります。通常は、ウェブサービスからのレスポンスを解析し、必要な値のみを抽出します。

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