Front-End Web & Mobile

Build a serverless store finder site using Amazon Location Service

Retail businesses are constantly aiming to increase accessibility and foot traffic at their physical store locations. To achieve this, potential customers must be able to accurately locate the most convenient retail location to visit. Providing information about the most accessible stores to potential customers via a convenient web or mobile application allows retailers to increase visits and improve customer experiences. Both a national retailer with thousands of locations and a small local hardware store with only a few locations can benefit, by making their retail locations more accessible to customers.

Amazon Location Service is a serverless, fully managed location-based service that allows developers to cost-effectively add location functionality to their applications using data from trusted commercial providers such as Esri, HERE Technologies, GrabMaps, as well as open data. Amazon Location allows you to easily augment your online storefront experience with location-based functionality to help drive customers to your premises.

In this blog post, we will show you how Amazon Location’s Maps, Places and Routing APIs can be used to implement a simple “store finder” web page which lists the physical stores that are most accessible to the customer, along with pertinent store information such as opening hours and postal address.

We will outline two approaches: the first pattern is designed for an example business with less than 20 stores distributed across a geographic area the size of the United Kingdom (UK). The second approach is targeted at a business with greater than 20 locations distributed across a geographic area the size of the United States (US).

Customer experience

The visitor of a typical store finder is presented with a simple webpage which presents two options:

  1. Agreeing to share their current location with their web browser, which is used as the departure position. This is useful when a customer is looking to visit a store right now.
  2. Entering text describing a location (such as a city name) into a field in the store finder site. The customer is then able to pick a location from a dropdown of suggested departure locations. Once a location is selected, this location is geocoded into a departure position. This is useful when a customer is planning to visit a store while they are visiting a location in the future.
 Figure 1: Navigating the landing page of a store finder

Figure 1: Navigating the landing page of a store finder

After the departure location is sent to the store finder back-end system, nearest stores are returned, along with the following store information that aids the customer’s experience:

  • Estimated duration and distance
  • Opening hours
  • Address

The stores are visually listed as markers on the map.

Figure 2: Displaying the list of nearest stores

Figure 2: Displaying the list of nearest stores

Solution overview

This solution reproduces this common use case, using a Vue.js 3.0 single page application for the front-end which provides the point of interaction for customers. The single page application is hosted using AWS Amplify Hosting, a fully managed service that lets frontend web and mobile developers easily build, ship, and host full-stack applications on AWS.

AWS services in the back-end provide the APIs for retrieving store information from a datastore, performing routing calculations using Amazon Location Service, and returning the relevant results back to the front-end. This solution makes use of Amazon API Gateway to host the APIs, AWS Lambda functions to implement the business logic, and either Amazon DynamoDB or Amazon Aurora Serverless to hold the store information depending on the pattern chosen.

Two customer types were considered when creating this solution to optimize for cost:

Solution Pattern Customer Type Example: Number of Stores Example: Country
1 “Small” < 20 United Kingdom
2 “Medium” or “Large” ≥ 20 United States

Architecture diagram

Shown below is the architectural diagram for both patterns.

Where the solutions differ between the 2 approaches, the colors blue (“pattern 1”) and red (“pattern 2”) have been used to highlight the differences.

Figure 3: Solution architecture diagram

Figure 3: Solution architecture diagram

How the solution works

This is how the solution works.

  1. Customer visits the store finder website hosted by Amplify Hosting. The website, built using the Vue.js 3 framework, uses aws-amplify, maplibre-gl-js-amplify and maplibre-gl JavaScript libraries to facilitate interaction with Amazon Cognito, and Amazon Location Service, as well as interactive map objects, such as vector tiles and markers.
  2. Customer authenticates using an Amazon Cognito user pool. The aws-amplify library handles the registration and authentication workflows, and retrieves temporary, scoped-down AWS credentials from Amazon Cognito’s identity pool. The AWS Identity and Access Management (IAM) role associated with authenticated access contains only the minimal permissions required for interacting with Amazon Location Service resources.
  3. Using maplibre-gl JavaScript libraries, the webpage displays an interactive map using vector tiles downloaded from Amazon Location using the Maps API. Markers are used to display departure location, and destination store locations when the results are returned.
  4. If customer enters custom text into the search field, Amazon Location’s SearchPlaceIndexForSuggestions Places API is invoked which returns a list of suggested places as a dropdown. When a customer selects one of the options, the GetPlace Places API for geocoding is invoked against the chosen PlaceId which returns location coordinates for the departure location. Optionally, the customer can opt to let the browser establish their current location using the Locate me button.
  5. The selected departure location is submitted to the solution’s custom APIs hosted using API Gateway. The request payload is hashed so that API Gateway can return responses from its cache for commonly requested departure positions (for example, Las Vegas, or London).
  6. This step differs depending on the pattern used:
    1. Pattern 1 – The API Gateway API invokes a Lambda function which returns all store locations from a DynamoDB table.
    2. Pattern 2 – The Lambda function uses a radial query to return a subset of candidate destination stores using PostgreSQL’s PostGIS geospatial capabilities (ST_DistanceSphere). The credentials for this Aurora Serverless PostgreSQL database are securely stored in AWS Secrets Manager.
  7. For both patterns, the list of returned destination stores is submitted to Amazon Location’s CalculateRouteMatrix Routes API to ascertain the estimated distance and duration to those destinations.
  8. A discreet shortlist of target stores and their metadata is returned to the front-end, and this information is presented back to the customer on the store finder webpage.

Simulated store locations

For the purposes of this demo, store locations have been simulated using the following data sources:

The store data is automatically loaded into the datastores by the provided templates. Refer to our GitHub repository to find out how the data import works.

Why use matrix routing?

When a customer is identifying the nearest store location to visit, the evaluated routes must be based on the customer’s chosen method of transport, and the current availability of the transportation network as curated by the location data providers. Simply calculating the great-circle distance between the customer’s departure position and candidate stores can yield unrealistic results for real-life journeys.

In the below example, Cardiff Airport is physically located closer to Minehead, UK. However, due to the presence of the body of water in-between, the more accessible airport from Minehead if using the road network is in fact Bristol Airport.

Figure 4: Using matrix routing to calculate nearest locations

Figure 4: Using matrix routing to calculate nearest locations

For pattern 2 of this solution, where there is a large number of possible destination stores, this solution uses a coarse-grained approach initially to generate a provisional list of candidate stores based on great-circle distances between coordinates to minimize the use of Amazon Location’s Routing API. This is more cost-effective when a business operates a large number of stores, as when using the Matrix Routing API, the pricing for the number of routes calculated is a function of the number of departure locations multiplied by the number of destination locations. This approach can scale to many hundreds of thousands of stores while keeping the cost per query consistent.

Furthermore, for both patterns, caching is enabled on API Gateway to ensure that responses to repeat queries are returned directly from the cache, and does not traverse the back-end infrastructure. This reduces the latency and cost of retrieving results.

Walkthrough

An aws-samples GitHub repository has been made available so that you can test this solution yourself. Following these steps will result in the full deployment of front-end and back-end resources for both serverless store finder patterns.

Refer to the repository for detailed instructions on how to customize the solution.

Prerequisites

For this walkthrough, you should have the following prerequisites in place:

Downloading the code

To install AWS SAM

  1. Follow the steps in the official documentation to install the latest release of the AWS SAM CLI for your operating system.
  2. Once successfully installed, run sam --version to return the AWS SAM CLI version.

Note: The AWS SAM CLI requires appropriate permissions to provision resources in the chosen AWS account. Ensure that access key and secret access keys have been created using IAM, and that aws configure has been used to register them locally on your machine.

  1. All front-end code, back-end code and AWS SAM templates required by both API patterns are stored in the serverless-store-finder GitHub repository.
  2. To download all required files to your local machine, run the following command.
git clone https://github.com/aws-samples/serverless-store-finder
  1. Navigate to the root of the downloaded repository, and install the JavaScript dependencies:
cd serverless-store-finder 
npm install
  1. Copy the .env.local.template file and rename it to .env.local.
cp .env.local.template .env.local

The .env.local.template file will be populated by the outputs from the AWS SAM template deployments.

You are now ready to deploy the AWS SAM templates.

Deploying the SAM templates

Store Finder – Core

The “Store Finder – Core” AWS SAM template will deploy the shared infrastructure resources required by both patterns, namely the Amazon Location map, place index and route calculator resources, and Amazon Cognito user and identity pools. This AWS SAM template will also create an empty Amplify Hosting app.

To deploy the Store Finder Core SAM template
  1. Navigate to the sam/core directory on your local machine.
cd sam/core
  1. Build the application.
sam build
  1. “Build Succeeded” message is displayed before continuing.
  2. Deploy the application.
sam deploy --guided
  1. When prompted enter the details chosen for your environment (you can keep the remainder as defaults):
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: <Your Store Finder "Core" Amazon CloudFormation stack name>
AWS Region [eu-west-1]: <Your AWS Region>
Parameter storeFinderAmplifySubdomain [demo]: <Amplify environment subdomain name used in URL>

In this example, we have used the stack name myStoreFinder-Core-v1 and our deployment is in AWS Region eu-west-1.

  1. Take a note of what name you have chosen for parameter “storeFinderAmplifySubdomain” as this is used later when the application is deployed to Amplify Hosting. In this example, we have chosen “demo”.
Figure 5: Deploying the SAM template for "Store Finder - Core"

Figure 5: Deploying the SAM template for “Store Finder – Core”

  1. Confirm that the “Successfully created/updated stack” message is shown.
Successful completion of create/update stack

Figure 6: Confirming successful deployment of SAM template “Store Finder – Core”

 

 

 

  1. Populate the missing Amazon Location and Amazon Cognito details in the .env.local file with the values outputted from the deployed Amazon CloudFormation stack.
VITE_AWS_REGION=<Your AWS Region>
VITE_AMAZON_COGNITO_IDENTITY_POOL_NAME=<storeFinderAmazonCognitoIdentityPoolName from the Store Finder "Core" Amazon CloudFormation stack output>
VITE_AMAZON_COGNITO_USER_POOL_NAME=<storeFinderAmazonCognitoUserPoolName from the Store Finder "Core" Amazon CloudFormation stack output>
VITE_AMAZON_COGNITO_USER_POOL_CLIENT_NAME=<storeFinderAmazonCognitoUserPoolClientName from the Store Finder "Core" Amazon CloudFormation stack output>
VITE_AMAZON_LOCATION_SERVICE_MAP=<storeFinderAmazonLocationServiceMapName from the Store Finder "Core" Amazon CloudFormation stack output>
VITE_AMAZON_LOCATION_SERVICE_PLACES_INDEX=<storeFinderAmazonLocationServicePlaceIndexName from the Store Finder "Core" Amazon CloudFormation stack output>

Store Finder – API Pattern 1

The “Store Finder – API Pattern 1” AWS SAM template will deploy the back-end API infrastructure and code required by Pattern 1, including the API Gateway, Lambda functions, and DynamoDB table. This API is fully functional standalone and is not dependent on API Pattern 2.

To deploy the Store Finder API Pattern 1 SAM template
  1. Navigate to the sam/api-pattern1 directory on your local machine.
    cd ../api-pattern1
  1. Build the application.
    sam build
  1. Confirm that the “Build Succeeded” message is displayed before continuing.
  2. Deploy the application.
    sam deploy --guided
  1. When prompted enter the details chosen for your environment (you can keep the remainder as defaults):

In this example, we have used the stack name “myStoreFinder-API-v1”.

Figure 7: Deploying the SAM template for "Store Finder - API Pattern 1"

Figure 7: Deploying the SAM template for “Store Finder – API Pattern 1”

  1. Confirm that the “Successfully created/updated stack” message is shown.
Figure 8: Confirming successful deployment of SAM template "Store Finder - API Pattern 1"

Figure 8: Confirming successful deployment of SAM template “Store Finder – API Pattern 1”

 

 

  1. Populate the missing API1 endpoint value in the .env.local file with the values outputted from the deployed CloudFormation stack.
VITE_APIGATEWAY_ENDPOINT_API1=<storeFinderAPIGatewayEndpoint from the Store Finder "API1" Amazon CloudFormation stack output>

Note: The Pattern 1 AWS SAM template contains a Lambda custom resource that will automatically load store data from the stores.json file. No further action is required, and API1 is now ready.

Store Finder – API Pattern 2

The “Store Finder – API Pattern 2” AWS SAM template will deploy the back-end API infrastructure and code required by Pattern 2, including the API Gateway, Lambda functions, Amazon Aurora Serverless V2 PostgreSQL database, and a Secrets Manager secret. This API is fully functional standalone and is not dependent on API Pattern 1.

To deploy the Store Finder API Pattern 2 SAM template
  1. Navigate to the sam/api-pattern2 directory on your local machine.
    cd ../api-pattern2
  1. Build the application.
    sam build
  1. Confirm that the “Build Succeeded” message is displayed before continuing.
  2. Deploy the application.
    sam deploy --guided
  1. When prompted enter the details chosen for your environment (you can keep the remainder as defaults):
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: <Your Store Finder "API2" Amazon CloudFormation stack name>
AWS Region [eu-west-1]: <Your AWS Region>
Parameter storeFinderCoreCloudFormationStackName []: <Name of the Store Finder "Core" Amazon CloudFormation stack>
Parameter storeFinderAuroraDBMasterUserName [admin_user] <Name of the PostgreSQL admin user account> 
Parameter storeFinderDatabaseTableName [tbl_postoffices]: <Name of table to be used in PostgreSQL database>

In this example, we have used the stack name “myStoreFinder-API2-v1”.

Figure 9: Deploying the SAM template for "Store Finder - API Pattern 2"

Figure 9: Deploying the SAM template for “Store Finder – API Pattern 2”

  1. Confirm that the “Successfully created/updated stack” message is shown. The deployment of this SAM template can take up to 20 minutes.
Figure 10: Confirming successful deployment of SAM template "Store Finder - API Pattern 2"

Figure 10: Confirming successful deployment of SAM template “Store Finder – API Pattern 2”

 

 

 

7. Populate the missing API2 endpoint value in the .env.local file with details from the outputs of the deployed CloudFormation stack.

VITE_APIGATEWAY_ENDPOINT_API2=<storeFinderAPIGatewayEndpoint from Store Finder "API2" Amazon CloudFormation Stack output>

Note: The Pattern 2 AWS SAM template contains a Lambda custom resource that will automatically load store data from the us-post-offices.csv file. No further action is required, and API2 is now ready.

Build and deploy the Vue.js application using Amplify Hosting

Note: In order to simplify this demo, Amplify Hosting is being used without integration with a software version control system. In real-life applications, it is strongly recommended that you integrate Amplify with a Git-based repository.

To build and deploy the Vue.js application
  1. Confirm that all the missing details have now been populated in the .env.local file by ensuring that no values remain blank.
  2. Build the front-end application from the root of the project folder structure.
cd ../.. 
npm run build
Figure 11: Confirming successful completion of npm run build

Figure 11: Confirming successful completion of npm run build

  1. Confirm that the Vue.js deployment files have been successfully created in the /dist
cd dist 
ls
  1. Compress all files in the folder using the The exact command may vary depending on the operating system you are using.
zip -r store-finder.zip .

Note that the zip operation needs to be performed inside the /dist directory and not at the folder-level. If you make subsequent changes to the .env.local file, you will need to rebuild the Vue.js application, and repeat these steps.

  1. Open the Amplify console, and select the Amplify app that was created by the “Store Finder – Core” AWS SAM template. Select Deploy without Git provider and choose Connect branch.
Figure 12: Deploying an Amplify app without a Git provider

Figure 12: Deploying an Amplify app without a Git provider

  1. For Environment name, give the identical name provided to the SAM template parameter storeFinderAmplifySubdomain (e.g. demo) during the deployment of the “Store Finder – Core” AWS SAM template.
  2. For Method, choose Drag and drop, and then upload the store-finder.zip file created earlier. This will automatically trigger the deployment to make the site available to the public.
Figure 13: Dragging and dropping the Vue.js deploying zip file

Figure 13: Dragging and dropping the Vue.js deploying zip file

  1. Wait for the “Deployment successfully completed” message to appear in the Amplify console.
  2. It is now possible to access your serverless store finder site using the URL provided by the Amplify environment’s Domain.
Figure 14: Accessing the store finder site using the Amplify app domain URL

Figure 14: Accessing the store finder site using the Amplify app domain URL

You will be initially prompted to create an account, and confirm your email address.

Note: This step has been introduced to secure the front-end of the demo, and back-end APIs, by enforcing authentication. Depending on your use case, you may decide that your store finder site needs to be publicly accessible to your website’s visitors This can be achieved by allowing unauthenticated guest access to Amazon Location resources, and by removing Cognito authentication from the API Gateway.

Figure 15: Creating an account using Amazon Cognito

Figure 15: Creating an account using Amazon Cognito

 

 

 

 

 

 

 

 

 

 

 

 

 

  1. Interact with the two API patterns by toggling the Select a country dropdown between “United Kingdom” and “United States”.
Figure 16: Testing the deployment of the serverless store finder site

Figure 16: Testing the deployment of the serverless store finder site

Cleaning up

To avoid incurring future charges, delete the CloudFormation stacks that have been provisioned in the AWS account.

Conclusion

This post demonstrated how Amazon Location Service can be used to create a simple, cost-effective website that allows a user to find the physical stores that are nearest to them. Using Amazon Location’s Maps, Places and Routes APIs, a visitor to your business’s store locator webpage can quickly identify the locations that are closest to their current, or future position. This information can then be used to make informed decisions about which store to visit, which will increase customer footfall.

Author bio

Alan Peaty

Alan is a Partner Solutions Architect helping Global Systems Integrators (GSIs) and their customers adopt AWS services. Prior to joining AWS, Alan worked as an architect at Systems Integrators such as IBM, Capita and CGI. Outside of work, Alan is a keen runner who loves to hit the muddy trails of the English countryside, and an Internet of Things (IoT) enthusiast.

Matt Nightingale

Matt is a Sr. Startup Solutions Architect at Amazon Web Services, helping enable startups to build, iterate, and scale cost-effective and scalable solutions on AWS. When not working with startups, Matt can be found building solutions that involve location-based services. Matt joined AWS in 2020 and is based in Boston, Massachusetts.