How to add a location search widget to your web app using Amazon Location Service
Tags: vue, aws, geospatial, amazonlocationservice
Published: 2022-07-13 20:44:00

Location information comes in different forms and formats from geographical coordinates (or longitude & latitude) to addresses and to place names. A common use case, when building geospatial apps, is to allow users to search for places, and convert geographic coordinates into addresses and vice versa.

[Amazon Location Service](https://aws.amazon.com/location/?trk=0d6a4738-ba96-4e67-9b74-2621db25aadb&sc_channel=el) lets you add location search functionality to your web and mobile applications. It supports:

* Converting text such as an address or a place name (or point of interest) into geographic coordinates, also known as geocoding.
* Turning geographic coordinates into an address or a place name (or point of interest), also known as reverse-geocoding.
* Responsive feedback to end-users as they are typing an address or a place name (or point of interest), also known as autocomplete or auto-suggest.

In this post, you will learn how you can add a location search widget to your web app using [Amazon Location Service’s Places API](https://docs.aws.amazon.com/location/latest/developerguide/places-concepts.html?trk=f55b5b23-b887-47e4-ae01-4316de84f2c4&sc_channel=el).  We will build the app using [AWS Amplify](https://docs.amplify.aws/) and [Vue](https://vuejs.org/) — We will create, deploy, and manage AWS resources using [Amplify CLI](https://docs.amplify.aws/cli/) and we will build the app components using [Amplify JavaScript](https://docs.amplify.aws/lib/q/platform/js/) and [MapLibre GL JS](https://maplibre.org/). The app will have a basemap with navigation controls and a location search widget with geocoding, reverse-geocoding, and autocomplete support.

{% embed https://youtu.be/FIRiL4gMS94 %}

## 1. Install and configure AWS Amplify

Before you start

* [Create an AWS account](https://portal.aws.amazon.com/billing/signup?trk=4173b244-a9c3-480e-bb61-f7c151208990&sc_channel=el), if you don’t have one already.
* Install [Node.js](https://nodejs.org/en/download/) (version 12.x or greater) and [npm](https://docs.npmjs.com/getting-started) (version 6.x or greater), if they are not already on your machine.

Now, install Amplify CLI.

```
npm install -g @aws-amplify/cli
```
Next, configure AWS Amplify. This will create a new IAM user with administrative access to your account to provision AWS resources for you.

```
amplify configure
```

```
Follow these steps to set up access to your AWS account:

Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue
```

Continue the process on the AWS Console. Create a user with `AdministratorAccess-Amplify` to your account to provision AWS resources for you.

![Add an IAM user for Amplify - Step 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qcic7b7abzg39gxhuzl4.png)
![Add an IAM user for Amplify - Step 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uuoxnguijb8i8ghx6zvp.png)
![Add an IAM user for Amplify - Step 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7m7pw3xn8yiat70r760y.png)

Once you create the user, Amplify CLI will ask you to provide the `accessKeyId` and the `secretAccessKey` to connect Amplify CLI with your newly created IAM user.

```
Enter the access key of the newly created user:
? accessKeyId: ••••••••••••••••
? secretAccessKey:  ••••••••••••••••
This would update/create the AWS Profile in your local machine
? Profile Name: default
```
## 2. Create a new project

Create a new Vue project using [Vite](https://vitejs.dev/).

```
npm create vite@latest
```
Choose a name for your project and pick `vue` as the framework and variant.

```
✔ Project name: location-search-widget
✔ Select a framework: › vue
✔ Select a variant: › vue
```
Next, go into your project’s root directory and install the dependencies.

```
cd location-search-widget
npm install
```
Then, initialize AWS Amplify within your project’s root directory.

```
amplify init
```
Choose a name for your Amplify project, set your desired configurations, and select your authentication profile. Amplify CLI will then initialize your project.

```
? Enter a name for the project locationsearchwidget
The following configuration will be applied:

Project information
| Name: locationsearchwidget
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: vue
| Source Directory Path: src
| Distribution Directory Path: dist
| Build Command: npm run-script build
| Start Command: npm run-script serve

? Initialize the project with the above configuration? Yes
Using default provider  awscloudformation
? Select the authentication method you want to use: AWS profile

For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html

? Please choose the profile you want to use default
```
Next, install the AWS Amplify library for JavaScript.

```
npm install aws-amplify
```
Then, add the following code to `src/main.js` to configure Amplify within your Vue app.

```javascript
...

import { Amplify } from "aws-amplify";
import awsconfig from "./aws-exports";

Amplify.configure(awsconfig);

...
```
Next, replace the content of `App.vue` with the following code.

```vue
<template>
</template>

<script setup>
</script>

<style>
</style>
```
Finally, add the following configuration to `vite.config`. 

```javascript
export default defineConfig({
  ...
  
  define: {
    global: {}
  }
});
```
## 3. Add auth configuration

We need to configure authentication in our app to specify how we want the frontend app access Amazon Location Service’s APIs. To do that, run the following command.

```
amplify add auth
```
We will stick with the defaults but you can choose advanced settings to make changes.

```
Using service: Cognito, provided by: awscloudformation
 
 The current configured provider is Amazon Cognito. 
 
 Do you want to use the default authentication and security configuration? Default configuration
 Warning: you will not be able to edit these selections. 
 How do you want users to be able to sign in? Username
 Do you want to configure advanced settings? No, I am done.
```
This will create an authentication resource, powered by Amazon Cognito, in your local environment.

## 4. Add a map

[Amplify Geo](https://docs.amplify.aws/lib/geo/getting-started/q/platform/js/) is a new addition to the Amplify family. It provides APIs and UI components that enable developers to add location functionality such as maps and place search to their web and mobile apps. Amplify Geo APIs are powered by Amazon Location Service and its UI components are built as a plugin for MapLibre.

Now, let’s add a map. First, create a map resource using Amplify CLI.

```
amplify add geo
```
Choose a name for your map and pick your preferred auth configuration. We will stick with the defaults but you can choose advanced settings to change your data provider or map style, for example.

```
? Select which capability you want to add: Map (visualize the geospatial data)
✔ Provide a name for the Map: · locationsearchmap
✔ Who can access this Map? · Authorized and Guest users
Available advanced settings:
- Map style & Map data provider (default: Streets provided by Esri)

✔ Do you want to configure advanced settings? (y/N) · no
```
This will create a map resource in your local environment. Next, push the changes to AWS.

```
amplfiy push
```
It may take a few minutes for the changes to deploy. Once it is done, you will have your authentication and map resources set up and ready to use.

Now, let’s render the map we just created. First, install  `maplibre-gl-js-amplify`,  which is a plugin for MapLibre GL JS that makes it easy to integrate with Amplify Geo.

```
npm install maplibre-gl-js-amplify
```
Then, open `App.vue` and add a `div` container for the map.

```vue
<template>
   <div id="map"></div>
</template>
```
Next, add a new map instance with navigation controls.

```vue
<script setup>
import maplibregl from "maplibre-gl";
import { createMap } from "maplibre-gl-js-amplify";

async function initializeMap() {
    const map = await createMap({
        container: "map", 
        center: [-114.067375, 51.046333],
        zoom: 16,
        hash: true
    });
    
    map.addControl(new maplibregl.NavigationControl(), "bottom-right");
}

initializeMap();
</script>
```
Finally, add the following CSS to produce a full screen map.

```vue
<style>
@import "maplibre-gl/dist/maplibre-gl.css";

body {
  margin: 0;
  padding: 0;
}
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
</style>
```

Now, if you run `npm run dev` in your terminal and go to your browser, you will see an interactive map on the page.

![An interactive map](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zoj45z4tdynyz9ylg4pk.png)

## 5. Add a location search widget

The next step is to create a location search resource using Amplify CLI.

```
amplify add geo
```
Choose a name for your location search index and pick your preferred auth configuration. We will stick with the defaults but you can choose advanced settings to change your data provider, for example.

```
? Select which capability you want to add: Location search (search by places, addresses, coordinates)
✔ Provide a name for the location search index (place index): · locationsearchwidget
✔ Who can access this search index? · Authorized and Guest users
Available advanced settings:
- Search data provider (default: HERE)
- Search result storage location (default: no result storage)

✔ Do you want to configure advanced settings? (y/N) · no
```
This will create the backend resources for your project in your local environment. Next, push the changes to AWS.

```
amplfiy push
```
It may take a few minutes for the changes to deploy. Once it is done, you will have a location search resource set up and ready to use.

Now, let’s add a location search UI component to our map. First, import `createAmplifyGeocoder` into `App.vue`. This will create an instance of [maplibre-gl-geocoder](https://github.com/maplibre/maplibre-gl-geocoder) with some pre-defined settings.

```vue
<script setup>
...

import { createMap, createAmplifyGeocoder } from "maplibre-gl-js-amplify";

...
</script>
```
Next, add a new map control for the location search component. 

```vue
<script setup>
...

async function initializeMap() {
   ...
   
   map.addControl(createAmplifyGeocoder(), "top-left");
}

...
</script>
```
Finally, import a CSS file into your app to style the location search component.

```vue
<style>
...

@import "@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css";

...
</style>
```
Now, if you save your project and go to your browser, you will see a location search widget on the map. 

![An interactive map with a location search widget](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqej4qhzh5ilza1s9n08.png)

## 6. Customizations

The Amplify Geo’s location search widget supports customization through a number of options, including:.

* `autocomplete`, which provides suggestions as users type in their input.
* `bbox`, which limits the results to a bounding box. By default, the location search widget returns results that are near the center of the map. If you add `bbox`, it will override the default behaviour.
* `countries`, which limits the results to specified countries using [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) three letter country codes, for example `CAN` for Canada.
* `language`, which limits the results to the specified language using a valid [BCP 47](https://tools.ietf.org/search/bcp47) language code, for example `en` for English.
* `limit`, which limits the maximum number of results returned in the API response. The default value is `5`.

Amplify Geo forms appropriate queries based on your customizations and invokes Amazon Location Service’s Places API to perform location search operations. See all the supported options for customization on [GitHub](https://github.com/aws-amplify/maplibre-gl-js-amplify/blob/main/API.md#createamplifygeocoder).

For this project, we will use `autocomplete`, `countries`, and `language`. 

```javascript
map.addControl(
    createAmplifyGeocoder({
      autocomplete: true,
      countries: "CAN",
      language: "en",
    }),
    "top-left"
  );
```
This will enable autocomplete and limit the search results to English and within Canada.

We will also add some UI customizations; we will use a custom icon for markers and add popups to markers. [Download](https://github.com/mepa1363/amazon-location-search-widget/blob/main/src/assets/MarkerIcon.svg) the SVG icon and put it in `src/assets`.

```vue
<script setup>
...

import markerIcon from "./assets/MarkerIcon.svg";

...

async function initializeMap() {
   ...

   const icon = new Image(35, 35);
   icon.src = markerIcon;

   map.addControl(
    createAmplifyGeocoder({
      ...
      
      marker: { element: icon },
      showResultMarkers: { element: icon },
      popup: { offset: 20 }
    }),
    "top-left"
  );
}

...
</script>
```
Finally, add some CSS to customize the style of the location search widget.

```vue
<style>
...

*:focus {
  outline: none !important;
}
.maplibregl-ctrl-top-left .maplibregl-ctrl {
  width: 400px !important;
  border-radius: 10px;
}
.suggestions {
  border-radius: 10px !important;
}
.maplibregl-ctrl-geocoder--input {
  height: 50px;
  padding: 0px 50px;
}
.maplibregl-ctrl-geocoder--icon-search {
  left: 15px;
  width: 25px;
  height: 35px;
}
.maplibregl-ctrl-geocoder--button {
  right: 15px !important;
  top: 15px !important;
}
.maplibregl-ctrl-geocoder--icon-loading {
  width: 25px;
  height: 25px;
  right: 15px !important;
  top: 15px !important;
}
</style>
```
Now, if you save your project and go to your browser, you will see the final result. You can search for addresses, place names, and geographic coordinates using the location search widget.

![An interactive web map with a customized location search widget](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hosx595zhu45lpxfrgy.png)

## Wrap up

In this tutorial, you learned how you can add a location search widget to your web app using [Amazon Location Service’s Places API](https://docs.aws.amazon.com/location/latest/developerguide/places-concepts.html?trk=f55b5b23-b887-47e4-ae01-4316de84f2c4&sc_channel=el). You can use this project as a starting point for building apps with maps and search functionality and customize it to fit your purpose. Here are a few things you can do:

* Include a number of different map styles using a layer control — see [my previous post](https://dev.to/mepa1363/how-to-build-an-interactive-map-using-amazon-location-service-and-maplibre-gl-js-280h) for a walkthrough.
* Use the location search widget options to provide a personalized experience for you users, for example setting the language property based on their IP or exposing geospatial filtering options using the bounding box property.
* Adjust the position of map controls such as the navigation controls and the location search widget or change their style to match your brand.

If you’d like to delete the AWS resources that you have created for this project, run `amplify delete`.

The code for this project is on [GitHub](https://github.com/mepa1363/amazon-location-search-widget). I’d love to hear your feedback, so please reach out to me if you have any questions or comments.