Amazon Location SDKとAPIキーで住所検索機能を構築してみた

![img](https://memo.dayjournal.dev/images/try-104_01.gif)

![img](https://memo.dayjournal.dev/images/try-104_02.png)

<br>

#### Amazon Location SDKとAPIキーで住所検索機能を構築してみました :tada:  

これまでAmazon Location Serviceを利用するには、[手動で設定](https://qiita.com/dayjournal/items/ff803c448d5419398e1e)をおこなうか、[Amplify Geoで設定](https://qiita.com/dayjournal/items/ecf954bcf43206f1b093)という選択肢がありました。そして、[Amazon Location SDK](https://docs.aws.amazon.com/location/latest/developerguide/dev-location-libraries.html)とAPIキー機能が今年発表され、選択肢がさらに広がりました。Amazon Location SDKを利用することで手動での設定も手軽になりました。今回は、この新機能を利用した住所検索機能について紹介したいと思います！

<br>

GitHubに作成した環境を公開しています。ぜひご利用ください!  

https://github.com/mug-jp/maplibregljs-amazon-location-service-place-indexes-starter

<br>

## 事前準備

- Amazon Location ServiceのAPIキー作成  

https://memo.dayjournal.dev/memo/amazon-location-service-004

https://memo.dayjournal.dev/memo/amazon-location-service-005

- MapLibre GL JSとAmazon Location Serviceを手軽に始めるビルド環境を利用  

https://github.com/mug-jp/maplibregljs-amazon-location-service-starter

実行環境

- node v20.6.1
- npm v9.8.1

<br>

## MapLibre GL JS & Amazon Location Service スターターの利用方法
既存のスターターを利用し、住所検索機能を構築します。ローカル環境にforkまたはダウンロードし動作確認をします。

<br>

パッケージをインストールします。

```shell
npm install
```

ローカルサーバーを起動します。

```shell
npm run dev
```

マップが表示されます。

![img](https://memo.dayjournal.dev/images/try-104_03.png)

<br>

## Amazon Location SDKのインストール
次に、Amazon Location SDKの必要なライブラリをインストールします。インストールすることでAPIの認証やMapLibre GL JSとの組み合わせが手軽になります。

<br>

AWS SDKをインストールします。"client-location"はAmazon Location Serviceを操作できるSDKです。

```shell
npm install @aws-sdk/client-location
```

"amazon-location-utilities-auth-helper"をインストールします。Amazon Location ServiceのAPIキーとCognitoの認証が手軽になるライブラリです。

```shell
npm install @aws/amazon-location-utilities-auth-helper
```

"amazon-location-utilities-datatypes"をインストールします。Amazon Location ServiceのレスポンスをGeoJSON形式に変換してくれるライブラリです。

```shell
npm install @aws/amazon-location-utilities-datatypes
```

<br>

"amazon-location-utilities-datatypes"について、MapLibre GL JSと組み合わせると一部利用しにくかったため、オプション機能を追加するコントリビュートをしました！

https://github.com/aws-geospatial

<br>

## 住所検索機能の構築
最後に、実際に住所検索機能を構築します。スターターから一部のファイル変更をします。

<br>

全体構成
![img](https://memo.dayjournal.dev/images/try-104_04.png)

<br>

#### package.json

```json
{
  "name": "maplibregljs-amazon-location-service-place-indexes-starter",
  "version": "3.3.1",
  "description": "",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "keywords": [],
  "author": "MapLibre User Group Japan",
  "license": "ISC",
  "devDependencies": {
    "typescript": "^5.2.2",
    "vite": "^4.4.9"
  },
  "dependencies": {
    "@aws-sdk/client-location": "^3.433.0",
    "@aws/amazon-location-utilities-auth-helper": "^1.0.2",
    "@aws/amazon-location-utilities-datatypes": "^1.0.3",
    "maplibre-gl": "^3.3.1"
  }
}
```

<br>

#### .env
事前準備で作成したリージョン・マップAPIキー・マップ名・ジオコーディングAPIキー・ジオコーディング名をenvファイルに設定します。

```env
VITE_REGION = xxxxx
VITE_MAP_API_KEY = v1.public.xxxxx
VITE_MAP_NAME = xxxxx
VITE_PLACE_API_KEY = v1.public.xxxxx
VITE_PLACE_NAME = xxxxx
```

<br>

/src
#### main.ts

```typescript
import './style.css'
import 'maplibre-gl/dist/maplibre-gl.css';
import maplibregl from 'maplibre-gl';
import { LocationClient, SearchPlaceIndexForTextCommand } from "@aws-sdk/client-location";
import { placeToFeatureCollection } from '@aws/amazon-location-utilities-datatypes';
import { withAPIKey } from '@aws/amazon-location-utilities-auth-helper';

const region = import.meta.env.VITE_REGION;
const mapApiKey = import.meta.env.VITE_MAP_API_KEY;
const mapName = import.meta.env.VITE_MAP_NAME;
const placeApiKey = import.meta.env.VITE_PLACE_API_KEY;
const placeName = import.meta.env.VITE_PLACE_NAME;

async function initialize() {
    const authHelper = await withAPIKey(placeApiKey);
    const client = new LocationClient({
        region: region,
        ...authHelper.getLocationClientConfig()
    });

    const input = {
        IndexName: placeName,
        Text: "サッポロファクトリー",
    };
    const command = new SearchPlaceIndexForTextCommand(input);
    const response = await client.send(command);
    const featureCollection = placeToFeatureCollection(response, {
        flattenProperties: true
    });

    const map = new maplibregl.Map({
        container: 'map',
        style: `https://maps.geo.${region}.amazonaws.com/maps/v0/maps/${mapName}/style-descriptor?key=${mapApiKey}`,
        center: [139.767, 35.681],
        zoom: 11,
    });
    map.addControl(
        new maplibregl.NavigationControl({
            visualizePitch: true,
        })
    );

    map.on('load', function () {
        map.addSource("search-result", {
            type: "geojson",
            data: featureCollection
        });
        map.addLayer({
            'id': "search-result",
            'type': 'circle',
            'source': 'search-result',
            'layout': {},
            'paint': {
                'circle-color': '#007cbf',
                'circle-radius': 10
            }
        });
        map.on('click', 'search-result', (e) => {
            const coordinates = e.lngLat;
            const description = e.features![0].properties['Place.Label'];
            new maplibregl.Popup()
                .setLngLat(coordinates)
                .setHTML(description)
                .addTo(map);
        });
        map.on('mouseenter', 'search-result', () => {
            map.getCanvas().style.cursor = 'pointer';
        });
        map.on('mouseleave', 'search-result', () => {
            map.getCanvas().style.cursor = '';
        });
    });
}
initialize();
```

Amazon Location SDKを定義します。

```typescript
import { LocationClient, SearchPlaceIndexForTextCommand } from "@aws-sdk/client-location";
import { placeToFeatureCollection } from '@aws/amazon-location-utilities-datatypes';
import { withAPIKey } from '@aws/amazon-location-utilities-auth-helper';
```

APIキーの認証設定をします。

```typescript
const authHelper = await withAPIKey(placeApiKey);
const client = new LocationClient({
    region: region,
    ...authHelper.getLocationClientConfig()
});
```

テキストからジオコーディングをします。

```typescript
const input = {
    IndexName: placeName,
    Text: "サッポロファクトリー",
};
const command = new SearchPlaceIndexForTextCommand(input);
const response = await client.send(command);
```

ジオコーディングのレスポンスをGeoJSONに変換します。

```typescript
const featureCollection = placeToFeatureCollection(response, {
    flattenProperties: true
});
```

<br>

ローカルサーバーで確認

```sh
npm run dev
```

<br>

Amazon Location SDKとAPIキー機能を組み合わせて住所検索結果を表示することができました！

![img](https://memo.dayjournal.dev/images/try-104_05.png)  

<br>

#### 他の例も紹介します！

<br>

IDからジオコーディングをします。

```typescript
import { LocationClient, GetPlaceCommand } from "@aws-sdk/client-location";

...

    const input = {
        IndexName: placeName,
        PlaceId: "AQABAFkA9d5eLnjB7XKy9_p0QX3oXD4nrLodHDtIvvzOwEyHbBx9m7LhmUP9WoNILhCrNzsL_DzOmUqagzNOgEabayDDLe6Oxh0rXolepvlZamPS5Q4KX41udsz856yYG6UdXqO6JmoLazImn-Isq2p20k5q_0902-uClFkGTw"
    };
    const command = new GetPlaceCommand(input);

...

```

<br>

![img](https://memo.dayjournal.dev/images/try-104_06.png)  

<br>

指定位置からリバースジオコーディングをします。


```typescript
import { LocationClient, SearchPlaceIndexForPositionCommand } from "@aws-sdk/client-location";

...

    const input = {
        IndexName: placeName,
        Position: [139.767, 35.681],
    };
    const command = new SearchPlaceIndexForPositionCommand(input);

...

```

<br>

![img](https://memo.dayjournal.dev/images/try-104_07.png)  

<br>
<br>

MapLibre GL JS・Amazon Location Serviceについて、他にも記事を書いています。よろしければぜひ :bow:
<a href="https://memo.dayjournal.dev/tags/maplibregljs" target="_blank">tags - MapLibre GL JS</a>
<a href="https://memo.dayjournal.dev/tags/amazon-location-service" target="_blank">tags - Amazon Location Service</a>

やってみたシリーズ :grinning:
<a href="https://day-journal.com/memo/tags/Try" target="_blank">tags - Try</a>

https://qiita.com/dayjournal/items/3e24f750d24af33182be

https://qiita.com/dayjournal/items/5e769f44e82d959a3279

https://qiita.com/dayjournal/items/b633883f48b4bdd91a75

https://aws.amazon.com/jp/builders-flash/202308/use-3d-map-library-location-service/?awsf.filter-name=*all

https://aws.amazon.com/jp/builders-flash/202301/use-map-library-location-service/?awsf.filter-name=*all

<br>
<br>

<a href="https://dayjournal.booth.pm" target="_blank"><img src="https://day-journal.com/memo/images/etc/book.png" alt="book"></a>