🍆

位置情報APIで経緯度を取得して、現在地から郵便番号を取得する【Amazon Location Service + Next.js】

2022/05/08に公開

なんだかんだやってみた結論

https://geoapi.heartrails.com/api.html 無料で使わせてくれるコレでいいんじゃないかと感じている...。無料の怖さはあるけど、個人開発勢としては無料ほど嬉しいものはない。(自由入力の検索もAmazon Location Serviceよりもいい感じなのよぉ...。)


navigator.geolocation.getCurrentPosition() を使うことで現在地情報を取得できますが、この値を用いることで現在地から郵便番号を取得する(逆ジオコーディングと呼ばれるようです)、という仕組みを簡単に実装することができます。(Google MapsのGeocoding APIでも同様のことができますが、料金が1/10ぐらい全く違うっぽいです。正しく理解できているかは自信がありません...。)

※リージョンには注意しながら作業進めていきましょう。

1. Amazon Location Serviceの設定をする

1-1. IAMユーザーを作成する

まずはAPIにアクセスするためのユーザーをIAMで作成する必要があります。
https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/home にアクセスして、ユーザーを追加しましょう。

「AWS 認証情報タイプを選択」で「アクセスキー・プログラムによるアクセス」にチェックを付けます。

次のページで「アクセス許可の設定」という画面になりますが、ここでは一旦何も設定せずに次に進みます。

これでユーザーの作成は完了です。

1-2. ポリシーを作成する

次にAmazon Location Serviceを使えるようにポリシーを作成します。
https://us-east-1.console.aws.amazon.com/iamv2/home#/policies にアクセスして、「ポリシーの作成」をクリックします。

正直、ポリシー周り全然分からないので下記の公式ドキュメントを参考にいい感じに作ってください。(郵便番号取得に最適な設定をコメントで教えて頂けると嬉しいです!)
https://docs.aws.amazon.com/location/latest/developerguide/security_iam_service-with-iam.html

サービス欄は「Location」を有効にしてください。

アクション欄は現在地情報から郵便番号の情報を取得するには SearchPlaceIndexForPositionCommand() という関数を使用するため、 SearchPlaceIndexForPosition というアクションを有効にする必要があります。

リソース欄やリクエスト条件欄についてはよく分からないのでご自身でご判断頂ければと思います。

1-3. 作成したポリシーをIAMユーザーに適用する

ポリシーはIAMユーザーに適用することで初めて使えるようになります。
https://us-east-1.console.aws.amazon.com/iamv2/home#/users
にアクセスして、先程作成したIAMユーザーを選択してください。

「Permissons policies」から「アクセス権限の追加」をクリックします。

「既存のポリシーを直接アタッチ」から先程作成したポリシーの名前を入力して検索します。

作成したポリシーにチェックを入れて保存してポリシーの適用は完了です。

1-4. Amazon Location Serviceでインデックスを作成する

https://ap-northeast-1.console.aws.amazon.com/location/home?region=ap-northeast-1#/ にアクセスして、「Create place index」をクリックしてインデックスを作成します。

「Name」 にはインデックスの名前を入力します。適当でOKです。

「Data provider」はどのエンジンを使うかを選択できるようです。Esriというサービスからデータを得るか、HERE というサービスからデータを取得するかを選択できます。どちらが良いかはよく分かりません。データの構造が若干違うようですので、この辺りは色々触りながらご判断ください。

「Data storage options」では結果を保存するかどうかを設定できるようです。
料金表 を見て頂きたいのですが、恐らくこの表の中の「保存された結果」というものが「Yes, results will be stored」を選択したときの料金だと思われます。ということは、保存すると高額になるので、結果は保存しない方が安価で利用できるものだと解釈しています。(正しく理解できているかは分かりません。)そのため、今回は「No, single use only」を選択しました。

あとは最後の欄をチェック付けて同意し、「Create place index」でインデックスを作成しましょう。これでAWSでの操作は完了です。


2. Next.js の API Routes で位置情報から郵便番号を取得する仕組みを構築する

2-1. 必要なパッケージをインストールする

npm i aws-sdk

Next.jsのプロジェクトフォルダ内で上記コマンドを実行して、「aws-sdk」をインストールします。

2-2. API Routes からAmazon Location Serviceを叩くようにする。

それでは、Next.js の apiディレクトリに適当なファイルを作成して「位置情報から郵便番号を取得するAPI」を作っていきます。(記事用に型書くの面倒だったのでjsファイルでご容赦ください...。)

/api/sample.js
import { LocationClient, SearchPlaceIndexForPositionCommand } from '@aws-sdk/client-location'

export default async function handler(req, res) {
  const { method } = req

  if (method === 'GET') {
    res.status(400).json({
      code: 400,
      message: '不正なリクエストのため処理が中断されました。',
      postalcode: undefined
    })
    return
  }

  if (method === 'POST') {
    const { lng, lat } = req.body

    const client = new LocationClient({
      credentials: {
        accessKeyId: 'hoge', // アクセスキー
        secretAccessKey: 'hogehoge' // シークレットキー
      },
      region: 'ap-northeast-1'
    })

    const command = new SearchPlaceIndexForPositionCommand({
      IndexName: 'hogehoge', // Amazon Location Serviceで作成したインデックス名を入力します
      Position: [lng, lat]
    })

    const results = await client.send(command)

    const { PostalCode } = results.Results[0].Place

    console.log(PostalCode)

    res.status(200).json({
      code: 200,
      message: 'リクエストが正しく処理されました。',
      postalcode: PostalCode
    })
    return
  }
}

lnglatの値をPOSTすると、座標から郵便番号を返却するという内容です。


results.Results[0] の中身は下記のような結果が入ってくれています。

この内 PostalCodeを抽出すれば郵便番号が取得できる、という仕組みです。

あとはフロント側で navigator.geolocation.getCurrentPosition() を使って座標を取得し、座標をPOSTすることで結果を取得することができるようになります。(多分バレたと思いますが記事を書くのが面倒になったので急に締めました...笑)

精度としてはPCだとやや雑ですが、スマホだと割りと近いところを示してくれます。(navigator.geolocation.getCurrentPosition() 側の問題なのでAmazon Location Serviceは悪くないです。)

APIリファレンス

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-location/index.html

使ってみて思ったこと

Google Geocoding APIは精度が高くググラビリティが大変素晴らしい。しかし、質が高い分、料金も高いので、極力使わない方向で考えるべきかも。

◆郵便番号から郵便番号の有効性のチェックと直接エリア名を取得する場合
節約的な意味でzipcloudのAPIを使わせてもらった方がいいかも。
http://zipcloud.ibsnet.co.jp/doc/api

◆位置情報からエリア名、郵便番号を取得する場合
Amazon Location Serviceの SearchPlaceIndexForPositionCommand() で取得するといい感じ。費用も安く済むはず。

無料で済ませるなら http://geoapi.heartrails.com/api.html も良いかも?

◆自由入力のテキストでエリア名、郵便番号を取得する場合
Google Geocoding APIを使った方がいいかも。ただし料金が高いので上記2パターンを分岐処理して、自由入力の検索は滅多に来ないように処理すべきと思われる。
建物名、店舗名、住所などで自由に検索することができる。
Amazon Location Serviceでは自由入力のテキスト SearchPlaceIndexForTextCommand() では郵便番号の取得ができなかった。(レスポンスは下記のような感じ)

※丁目まで含めると郵便番号が入ってくる模様。郵便番号を特定できるほどエリアを狭める必要があるらしい。

▼コマンド例

▼レスポンスの例

※Data providerをEsriとHEREどちらも試してみたが、TimeZoneが追加されるかどうかの違いだけっぽかったです。(詳しくみてないので知らない)

Discussion