Google Maps Platform ウェブサービスは、地図アプリケーションに地理データを提供する Google サービスへの HTTP インターフェースのコレクションです。
このガイドでは、ウェブサービス リクエストの設定とサービス レスポンスの処理に役立つ一般的な方法について説明します。Address Validation API の詳細なドキュメントについては、デベロッパー ガイドをご覧ください。
ウェブサービスとは
Google Maps Platform ウェブサービスは、外部サービスから Maps API データをリクエストし、そのデータを地図アプリケーション内で使用するためのインターフェースです。これらのサービスは、Google Maps Platform 利用規約のライセンス制限に従って、地図と組み合わせて使用するように設計されています。
Maps API ウェブサービスは、特定の URL への HTTP(S) リクエストを使用し、URL パラメータや JSON 形式の POST データを引数としてサービスに渡します。通常、これらのサービスは、アプリケーションで解析や処理を行うために、レスポンス本文で JSON 形式のデータを返します。
HTTPPOST リクエストを validateAddress メソッドに送信して、住所を検証します。
https://addressvalidation.googleapis.com/v1:validateAddress
検証する住所を定義するリクエストに JSON 本文を渡します。
注: すべての Address Validation 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 での使用法 |
|---|---|---|
| 英数字 | 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 クライアントの設計が不十分な場合、インターネットと 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×tamp=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 リクエストがクライアント間で同期されないようにする必要があります。
たとえば、現在のタイムゾーンの時刻を表示するアプリケーションについて考えてみましょう。このアプリケーションは、クライアント オペレーティング システムでアラームを設定し、1 分の開始時に起動して、表示される時刻を更新できるようにします。アプリは、そのアラームに関連する処理の一部として API 呼び出しを行ってはなりません。
固定アラームに応じて API 呼び出しを行うと、API 呼び出しが時間の経過とともに均等に分散されるのではなく、異なるデバイス間でも分の開始に同期されるため、適切ではありません。不適切に設計されたアプリケーションでは、毎分の開始時に通常の 60 倍のトラフィックの急増が発生します。
代わりに、2 つ目のアラームをランダムに選択した時刻に設定するという設計が考えられます。この 2 番目のアラームがトリガーされると、アプリは必要な API を呼び出して結果を保存します。アプリが 1 分の開始時に表示を更新する場合は、API を再度呼び出すのではなく、以前に保存した結果を使用します。この方法では、API 呼び出しが時間の経過とともに均等に分散されます。さらに、API 呼び出しによって、ディスプレイの更新時にレンダリングが遅れることはありません。
分の開始以外に、ターゲットにしないよう注意する必要がある一般的な同期時間は、時間の開始と、毎日の深夜 0 時の開始です。
レスポンスの処理
このセクションでは、これらの値をウェブサービス レスポンスから動的に抽出する方法について説明します。
Google マップ ウェブサービスは、わかりやすいレスポンスを提供しますが、ユーザー フレンドリーとは言えません。クエリを実行するときに、一連のデータを表示するのではなく、特定の値をいくつか抽出したい場合があります。通常は、ウェブサービスからのレスポンスを解析し、必要な値のみを抽出します。
使用する解析スキームは、JSON で出力を返すかどうかによって異なります。JSON レスポンスはすでに JavaScript オブジェクトの形式になっているため、クライアント上の JavaScript 自体で処理できます。