Front-End Web & Mobile

Build your own application for route optimization and tracking using AWS Amplify and Amazon Location Service

Many companies serve their customers “in the field.” These are broadly: 1) companies that have a field service business function, e.g., for the repair of equipment that they sell to their customers, and 2) companies that have a route sales business function, e.g., a Consumer Packaged Goods (CPG) company’s own or contract employees stocking the shelves of a retailer with the CPG company’s products (called direct-to-store delivery (DSD)).

In an earlier post, we described a solution that can benefit field services across industries and DSD route sales for food & beverage companies. In this post, we’ll demonstrate how you can build and run this solution yourself, which will prepare you to adapt this solution to your organization’s needs. We’ll demonstrate how AWS Amplify, a set of tools and features to build full-stack applications on AWS, integrates with Amazon Location Service, AWS AppSync, and AWS IoT Core to provide a reference solution for transportation and logistics tracking. Your application will enable a dispatcher to search and enter origin, destination, and waypoint locations on a map. The Amazon Location matrix routing feature calculates the time and distance between any two points on a map. Based on this feature, we provide an implementation that uses matrix routing as the input, and then calculates and displays a route on the map that provides the shortest time to complete the trip. The application also provides the ability to track a driver on the map as they complete their route by simulating an Internet of Things (IoT) sensor/device installed in their vehicle.

Solution overview

The solution is available for download with a detailed README. It’s divided into three components:

  1. Route entry – The Route entry component leverages Amplify React development with AWS AppSync and Amazon DynamoDB to enable a field service dispatcher to enter and store origin, destination, and waypoint locations using a map.
  2. Route calculation – The Route calculation component leverages AWS Lambda, Amazon Location matrix routing, and AWS AppSync to automatically create an optimized lowest cost route based on the shortest time to complete the trip, and then displays the optimized route on the map.
  3. Route tracking – The Route tracking component integrates the Amplify based React application with AWS App Sync, AWS IoT Core, and Amazon Location tracker to track our driver on the map as they complete their route. This component simulates an IOT sensor/device installed in the vehicle.

In this post, we’ll build the solution iteratively by completing the setup for each component. At every step, you can test a component before moving to the next stage. We expect this entire exercise to take 45-60 minutes to complete, depending on your experience level. If you need to take a break, then consider stopping after completing the setup of the first or second of the three solution components. The following architecture diagram depicts the AWS services involved in each of the components outlined above:

Figure 1: Route optimization and tracking using Amplify and Amazon Location

Prerequisites

We highly recommend using the AWS Cloud9 environment to run and deploy this solution. Alternatively, you can use any development environment of your choice.

Option 1: Setup Cloud9

  1. Go to the Cloud9 web console
  2. At the top right corner of the console, make sure that you’re using this region: Virginia (us-east-1)
  3. Select Create environment
  4. Name it RouteOptimizationWorkshop, and go to the Next step
  5. Select Create a new EC2 instance for environment (direct access) and pick m5.large
  6. Leave all of the environment settings as they are, and go to the Next step
  7. Select Create environment

Once the Cloud9 instance has started, open a new terminal and run the following commands:

  • echo -e "[default]\noutput=json\nregion=us-east-1" >> ~/.aws/config – this will set the default region for your AWS Command Line Interface (AWS CLI) and Amplify CLI commands
  • npm install --location=global @aws-amplify/cli@9.1.0 – this will install the Amplify CLI

Then, follow the steps described here to increase the default volume size.

Option 2: Locally on your machine

Solution setup – Route Entry

Step 0 – Clone the repo and install project dependencies

Clone the repo. While in the root of the project directory, run the following command to install all the dependencies:

git clone https://github.com/aws-samples/aws-intelligent-route-optimization-tracking
cd aws-intelligent-route-optimization-tracking
npm install

Step 1 – Create a new Amplify project

The codebase that we’ve just cloned comes with a folder containing the backend configuration. Since we’ll create it from scratch, delete the amplify folder (i.e., rm -rf amplify).

Then, while still in the project’s root, run the following command (amplify init) and follow the prompts to initialize a new Amplify project:

amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project awssupplychaindemo
The following configuration will be applied:

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

? 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
Adding backend environment dev to AWS Amplify app: d2mrv0blz6ulx8
⠙ Initializing project in the cloud...

# Additional logs were removed for brevity

✅ Successfully added resource supplychainmap locally.

Step 2 – Create Amazon Location resources

Then, while still in your terminal and in the root of the project, run the amplify add geo command to create a new Amazon Location map resource:

amplify add geo
? Select which capability you want to add: Map (visualize the geospatial data)
✔ geo category resources require auth (Amazon Cognito). Do you want to add auth now? (Y/n) · yes
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? Email
Do you want to configure advanced settings? No, I am done.
✅ Successfully added auth resource awssupplychaindemoc6a313aa locally

✅ Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

✔ Provide a name for the Map: · supplychainmap
✔ Who can access this Map? · Authorized users only
Available advanced settings:
- Map style & Map data provider (default: Streets provided by Esri)

✔ Do you want to configure advanced settings? (y/N) · yes
✔ Specify the map style. Refer https://docs.aws.amazon.com/location-maps/latest/APIReference/API_MapConfiguration.html · Explore (data provided by HERE)

Next, run the command once again – but with different answers to the prompts – to create a Place index resource:

amplify add geo
? Select which capability you want to add: Location search (search by places, addresses, coordinates)
✔ Provide a name for the location search index (place index): · supplychainplace
✔ Who can access this search index? · Authorized users only
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) · yes
✔ Specify the data provider of geospatial data for this search index: · HERE
✔ Do you want to cache or store the results of search operations? Refer https://docs.aws.amazon.com/location-places/latest/APIReference/API_DataSourceConfiguration.html (y/N) · yes

Next, add an Amplify custom resource. These custom resources are Lambda backed resources. They are needed here because at the moment Amplify CLI doesn’t support creating Route calculator and Tracker resources:

amplify add custom
✔ How do you want to define this custom resource? · AWS CDK
✔ Provide a name for your custom resource · customLocation
✅ Created skeleton CDK stack in amplify/backend/custom/customLocation directory

Before starting to define resources in the AWS Cloud Development Kit (AWS CDK)  stack, you must add a new dependency to the stack. Open the amplify/backend/custom/customResourceXXXXX/package.json file in your text editor and replace its content with this:

{
  "name": "custom-resource",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "@aws-amplify/cli-extensibility-helper": "^2.0.0",
    "@aws-cdk/core": "~1.156.1",
    "@aws-cdk/aws-iam": "~1.156.1",
    "@aws-cdk/aws-location": "~1.156.1"
  },
  "devDependencies": {
    "typescript": "^4.2.4"
  }
}

After having modified the file above, change the directory to the amplify/backend/custom/customLocation directory, and then run npm i in your terminal to install the dependencies that we’ve just added.

These extra dependencies are needed for the AWS CDK stack to create the Amazon Location Tracker and RouteCalculator.

Open the amplify/backend/custom/customLocation/cdk-stack.ts file and  add the code from  amplify/backend/custom/customLocation/cdk-stack.ts  from our solution’s repository

Next, you must allow the authenticated AWS Identity and Access Management (IAM) role to access the Route calculator resource. This will allow logged-in users to call the geo:CalculateRoute API.

Go back to the main directory of the project and run the following command to extend the Amplify generated IAM role:

amplify override project
✅ Successfully generated "override.ts" folder at amplify/backend/awscloudformation
✔ Do you want to edit override.ts file now? (Y/n) · no

Next, add the following statement to the override.ts file that was generated (amplify/backend/awscloudformation/override.ts):

import { AmplifyRootStackTemplate } from "@aws-amplify/cli-extensibility-helper";

export function override(resources: AmplifyRootStackTemplate) {
  const authRole = resources.authRole;

  const basePolicies = Array.isArray(authRole.policies)
    ? authRole.policies
    : [authRole.policies];

  authRole.policies = [
    ...basePolicies,
    {
      policyName: "amplify-permissions-custom-resources",
      policyDocument: {
        Version: "2012-10-17",
        Statement: [
          {
            Resource: {
              "Fn::Sub":
                "arn:aws:geo:${AWS::Region}:${AWS::AccountId}:route-calculator/routecalculator_supplychain",
            },
            Action: ["geo:CalculateRoute*"],
            Effect: "Allow",
          },
        ],
      },
    },
  ];
}

Step 3: Initialize the AWS AppSync GraphQL API

From the root of the project folder, continue by adding an AWS AppSync API using the Amplify CLI.

Note that when creating the AppSync API, make sure to set Amazon Cognito User Pool as Authorization mode. Do this by selecting “Authorization Mode” and selecting “Amazon Cognito User Pool” after selecting “GraphQL”. If you’ve already stepped through the options, then you can update the GraphQL API by running `amplify update api` and selecting “Authorization Mode“.

amplify add api
? Select from one of the below mentioned services: GraphQL
? Here is the GraphQL API that we will create. Select a setting to edit or continue Authorization modes: API key (default, expiration time: 7 days from now)
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Configure additional auth types? No
? Here is the GraphQL API that we will create. Select a setting to edit or continue Continue
? Choose a schema template: Blank Schema
✅ GraphQL schema compiled successfully.

Edit your schema at amplify/backend/api/awssupplychaindemo/schema.graphql or place .graphql files in a directory at amplify/backend/api/awssupplychaindemo/schema
✔ Do you want to edit the schema now? (Y/n) · no
Edit the file in your editor: amplify/backend/api/awssupplychaindemo/schema.graphql

Before deploying the resources, open the file amplify/backend/api/awssupplychaindemo/schema.graphql and replace its content with the following schema:

type Coords {
  lng: Float!
  lat: Float!
}

type Marker {
  point: Coords!
  label: String
}

type Itinerary
  @model
  @auth(rules: [{ allow: owner, operations: [create, read, update, delete] }]) {
  id: ID!
  label: String!
  points: [Marker]!
  date: AWSDate!
  optimized: Boolean! @default(value: "false")
  hasStarted: Boolean! @default(value: "false")
  type: String!
    @index(
      name: "itinerariesByDate"
      queryField: "itinerariesByDate"
      sortKeyFields: ["date"]
    )
    @default(value: "itinerary")
}

Step 4: Push resources to the cloud

Note that if the Amplify CLI asks you to generate the schemas/models for the GraphQL API, answer NO. These files are already included in the base application.

amplify push

⠧Fetching updates to backend environment: dev from the cloud.GraphQL schema compiled successfully.

Edit your schema at amplify/backend/api/awssupplychaindemo/schema.graphql or place .graphql files in a directory at amplify/backend/api/fooddeliverydemo/schema
✔ Successfully pulled backend environment dev from the cloud.
⠦ Building resource api/awssupplychaindemo GraphQL schema compiled successfully.

Edit your schema at amplify/backend/api/awssupplychaindemo/schema.graphql or place .graphql files in a directory at amplify/backend/api/fooddeliverydemo/schema

    Current Environment: dev
┌──────────┬────────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name              │ Operation │ Provider plugin   │
├──────────┼────────────────────────────┼───────────┼───────────────────┤
│ Auth     │ awssupplychaindemoXxXXXxx  │ Create    │ awscloudformation │
├──────────┼────────────────────────────┼───────────┼───────────────────┤
│ Geo      │ mapXXXXxXxx                │ Create    │ awscloudformation │
├──────────┼────────────────────────────┼───────────┼───────────────────┤
│ Geo      │ placeindexxxXXXXXX         │ Create    │ awscloudformation │
├──────────┼────────────────────────────┼───────────┼───────────────────┤
│ Custom   │ locationResources          │ Create    │ awscloudformation │
├──────────┼────────────────────────────┼───────────┼───────────────────┤
│ Api      │ awssupplychaindemo         │ Create    │ awscloudformation │
└──────────┴────────────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
✅ GraphQL schema compiled successfully.

Edit your schema at /home/ec2-user/environment/my-workshop-app/amplify/backend/api/awssupplychaindemo/schema.graphql or place .graphql files in a directory at /home/ec2-user/environment/my-workshop-app/amplify/backend/api/awssupplychaindemo/schema
Overrides functionality is not implemented for this category
Overrides functionality is not implemented for this category
⠹ Building resource api/awssupplychaindemo✅ GraphQL schema compiled successfully.

Edit your schema at /home/ec2-user/environment/my-workshop-app/amplify/backend/api/awssupplychaindemo/schema.graphql or place .graphql files in a directory at /home/ec2-user/environment/my-workshop-app/amplify/backend/api/awssupplychaindemo/schema
? Do you want to generate code for your newly created GraphQL API No

At this stage, if you run npm start while in the project’s folder, you should be able to see the login screen as shown in the following image. Go ahead and create an account.

Figure 2: Login screen to sign in or create an account to access the solution

Once you create an account, you can create an itinerary and add or search for locations on the map as shown in the following image:

Figure 3: Add locations directly on the map as waypoints or destination addresses.

Figure 4: Search for locations to be added on the map as waypoints or destination addresses.

Solution setup – Route Calculation

Step 1: Create an Lambda layer

We’ll start by creating a new Layer that will contain a Logger utility from Lambda Powertools for TypeScript.

Lambda Powertools for TypeScript provides a suite of utilities for Lambda functions running on the Node.js runtime, to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more.

From the root of the project folder, run the following command:

amplify add function
? Select which capability you want to add: Lambda layer (shared code & resource used across functions)
? Provide a name for your Lambda layer: powertools
? Choose the runtime that you want to use: NodeJS
? The current AWS account will always have access to this layer.
Optionally, configure who else can access this layer. (Hit <Enter> to skip)
✅ Lambda layer folders & files created:
amplify/backend/function/awssupplychaindemopowertools

Next steps:
Move your libraries to the following folder:
[NodeJS]: amplify/backend/function/awssupplychaindemopowertools/lib/nodejs

# Additional logs were removed for brevity

Next, change directory to the amplify/backend/function/awssupplychaindemopowertools/lib/nodejs folder that was added to your project, and run npm i @aws-lambda-powertools/logger@latest to install the AWS Lambda Powertools Logger that you’ll use to create structured logs for our Lambda functions.

Create a file at amplify/backend/function/awssupplychaindemopowertools/opt/powertools.js and add the following code:

const { Logger } = require("@aws-lambda-powertools/logger");

const awsLambdaPowertoolsVersion = "1.0.2";

const logger = new Logger({
  persistentLogAttributes: {
    logger: {
      name: "@aws-lambda-powertools/logger",
      version: awsLambdaPowertoolsVersion,
    },
  },
  logLevel: "DEBUG",
});

module.exports = {
  logger,
};

Step 2: Create the Lambda function for shortest time calculation based on matrix routing

Next, let’s add a new Lambda function to our project. We’ll call this function routeOptimizerFn and use it to perform the route optimization using the Matrix Routing API.

Note that when presented with multiple options from the Amplify CLI, you can make your selection using the spacebar.

amplify add function
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: routeOptimizerFn
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
- Environment variables configuration
- Secret values configuration

? Do you want to configure advanced settings? Yes
? Do you want to access other resources in this project from your Lambda function? Yes
? Select the categories you want this function to have access to: api, storage
? Select the operations you want to permit on Itinerary:@model(appsync) read, update

You can access the following resource attributes as environment variables from your Lambda function
API_AWSSUPPLYCHAINDEMO_GRAPHQLAPIIDOUTPUT
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_ARN
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_NAME
ENV
REGION
? Do you want to invoke this function on a recurring schedule? No
? Do you want to enable Lambda layers for this function? No
? Do you want to configure environment variables for this function? Yes
? Enter the environment variable name: ROUTE_CALCULATOR_NAME
? Enter the environment variable value: routecalculator_supplychain
? Select what you want to do with environment variables: Add new environment variable
? Enter the environment variable name: POWERTOOLS_SERVICE_NAME
? Enter the environment variable value: routeOptimizerFn
? Select what you want to do with environment variables: I\'m done

You can access the following resource attributes as environment variables from your Lambda function
ENV
REGION
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_NAME
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_ARN
API_AWSSUPPLYCHAINDEMO_GRAPHQLAPIIDOUTPUT
ROUTE_CALCULATOR_NAME
POWERTOOLS_SERVICE_NAME
? Do you want to configure secret values this function can access? No
? Do you want to edit the local lambda function now? No
Successfully added resource routeOptimizerfn locally.

# Additional logs were removed for brevity

Next, in the amplify/backend/function/routeOptimizerFn/src folder, run the following command with your terminal:

npm i @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb @aws-sdk/client-location

Then, open the amplify/backend/function/routeOptimizerFn/src/index.js file and replace its contents with the ones that you can find in the amplify/backend/function/routeOptimizerFn/src/index.js of our repository.

Finally, open the amplify/backend/function/routeOptimizerFn/custom-policies.json file and replace its contents with the following:

[
  {
    "Action": ["geo:CalculateRouteMatrix"],
    "Resource": [{
     "Fn::Sub": "arn:aws:geo:${AWS::Region}:${AWS::AccountId}:route-calculator/routecalculator_supplychain"
    }]
  }
]

Step 3: Add a new GraphQL mutation to the schema

Next, we must add a new GraphQL mutation to the schema so that AWS AppSync knows that we want to use the routeOptimizerFn function for this mutation.

Open the schema file in the amplify/backend/api/awssupplychaindemo/schema.graphql file and add the following mutation at the bottom of the file. Note that we’re using the -${env} suffix: this is a convenience feature that Amplify CLI provides that will automatically replace the -${env} suffix with the current environment name.

type Mutation {
  optimized(id: ID): Itinerary @function(name: "routeOptimizerFn-${env}")
}

Then, run amplify push to update your backend resources. Follow and confirm the prompts displayed.

Note that if the Amplify CLI asks you to generate the schemas/models for the GraphQL API, answer NO. These files are already included in the base application.

Once the Amplify CLI has finished deploying, you can start the application again (npm start). While in the map view of the itinerary, you can now select the “Optimize” button to trigger the route optimization.

Figure 5: Select the optimize button to create a shortest time route on the map.

Solution setup – Route Tracking

Step 1: Create the Lambda function to simulate a vehicle driving on the route

Create the first Lambda function that will be used to simulate a truck driving on the route in the map. From the root of the project folder, run the following command:

amplify add function
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: deviceSimulatorFn
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
- Environment variables configuration
- Secret values configuration

? Do you want to configure advanced settings? Yes
? Do you want to access other resources in this project from your Lambda function? Yes
? Select the categories you want this function to have access to- api, storage
? Select the operations you want to permit on Itinerary:@model(appsync) read

You can access the following resource attributes as environment variables from your Lambda function
API_AWSSUPPLYCHAINDEMO_GRAPHQLAPIIDOUTPUT
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_ARN
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_NAME
ENV
REGION
? Do you want to invoke this function on a recurring schedule? No
? Do you want to enable Lambda layers for this function? Yes
? Provide existing layers or select layers in this project to access from this function (pick up to 5): awssupplychaindemopowertools
? Do you want to configure environment variables for this function? Yes
? Enter the environment variable name: ROUTE_CALCULATOR_NAME
? Enter the environment variable value: routecalculator_supplychain
? Select what you want to do with environment variables: Add new environment variable
? Enter the environment variable name: POWERTOOLS_SERVICE_NAME
? Enter the environment variable value: deviceSimulatorFn
? Select what you want to do with environment variables: I'm done

You can access the following resource attributes as environment variables from your Lambda function
ENV
REGION
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_NAME
API_AWSSUPPLYCHAINDEMO_ITINERARYTABLE_ARN
API_AWSSUPPLYCHAINDEMO_GRAPHQLAPIIDOUTPUT
ROUTE_CALCULATOR_NAME
? Do you want to configure secret values this function can access? No
? Do you want to edit the local lambda function now? No
Successfully added resource devicesimulatorfn locally.

# Additional logs were removed for brevity
Next, navigate to the function's folder (amplify/backend/function/devicesimulatorfn/src) with your terminal, and run the following commands to create the directory structure that we need, as well as install some dependencies:
npm i @aws-sdk/client-location @turf/along @turf/helpers aws-iot-device-sdk-v2
mkdir certs
touch utils.js
Then, open the utils.js file that you just created (full path amplify/backend/function/devicesimulatorfn/src/utils.js) and add the code in the utils.js file here in our GitHub repository.

Finally, open the index.js file and add the code in the index.js file here in our GitHub repository.

While editing this file, make sure to replace the value of the THING_ENDPOINT constant using the AWS IoT Core endpoint that corresponds to your AWS Region and account. Obtain your endpoint by running the following command:

aws iot describe-endpoint –endpoint-type iot:Data-ATS

The result should look like this:

{
  "endpointAddress": "[some-id]-ats.iot.[region-name].amazonaws.com"
}

Next, since you want this Lambda function to run for as long as possible, let’s extend the timeout duration from the default of 25 seconds to 15 minutes. To do so, open the amplify/backend/function/deviceSimulatorFn/deviceSimulatorFn-cloudformation-template.json file and find the line that has the "Timeout": 25 text, and replace it with "Timeout": 900 (15 minutes).

Finally, open the amplify/backend/function/devicesimulator/custom-policies.json file and add the following code. Replace the region-name and account-id with the values from your corresponding AWS Region and account.

[
  {
    "Action": ["geo:CalculateRoute"],
    "Resource": [{
      "Fn::Sub": "arn:aws:geo:${AWS::Region}:${AWS::AccountId}:route-calculator/routecalculator_supplychain"
    }]
  }
]

Step 2: Create the AWS IoT Core resources

Next, continue by running the following command to generate a new AWS IoT Core certificate that will be used by the function to connect to the IoT Core endpoint. This is one of the few manual steps that you must run, since it’s easier to manage this resource via the AWS CLI than with Amplify:

Navigate to the amplify/backend/function/devicesimulatorfn/src/certs folder and run the following command:

aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile "certificate.pem.crt" --public-key-outfile "public.pem.key" --private-key-outfile "private.pem.key"

The result should look like this:

{
"certificateArn": "arn:aws:iot:[region-name]:[account-id]:cert/xxxxx",
"certificatePem": "-----BEGIN CERTIFICATE-----\nxxxxxxxxxx==\n-----END CERTIFICATE-----\n",
"keyPair": {
"PublicKey": "-----BEGIN PUBLIC KEY-----\nxxxxx\n-----END PUBLIC KEY-----\n",
"PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nxxxxx\n-----END RSA PRIVATE KEY-----\n"
},
"certificateId": "[certificate-id]"
}

Note the certificateId key from the above output. You will use this to update the certificateId value in the iotResources custom resource that you create in the following.

Once again, we can use the amplify add custom command to create the IoT resources that we need with AWS CDK. From the root folder of the project, run the following command:

amplify add custom
✔ How do you want to define this custom resource? · AWS CDK
✔ Provide a name for your custom resource · iotResources
✅ Created skeleton CDK stack in amplify/backend/custom/iotResources directory
✔ Do you want to edit the CDK stack now? (Y/n) · no

Navigate to the file at amplify/backend/custom/iotResources/package.json and update the dependency list from the corresponding file in our GitHub repo.

While in the amplify/backend/custom/iotResources directory, run the npm i command to install these dependencies. Next, navigate to the amplify/backend/custom/iotResources/cdk-stack.ts file and update it with the contents of the iotResources/cdk-stack.ts from our repo. In this cdk-stack.ts file, find the line that looks like this:

const CERTIFICATE_ID = "[YOUR_CERTIFICATE_ID]";
// Identifier for the IoT Core Certificate, REPLACE THIS WITH YOUR CERTIFICATE ID

Replace the value between the quotes with the certificate ID that you created earlier.

Step 3: Create remaining Lambda functions

Now you must create the remaining Lambda functions needed for the Route Tracking component. Follow step-by-step instructions in Step 6: Create the remaining Lambda functions of our GitHub repo. Since you’ve already created the routeOptimizer function, skip creating it in these step-by-step instructions and create all of the other functions.

Step 4: Update the GraphQL schema

Now that we have added more functions, we must update the GraphQL schema to include custom mutations and queries. Navigate to the amplify/backend/schema/schema.graphql file. Update the content of the file so that it includes the following snippet.

Note that you should already have a type Mutation statement in it. Therefore, make sure to remove the existing one before you place the following one.

type Mutation {
  optimized(id: ID): Itinerary @function(name: "routeOptimizerFn-${env}")
  startItinerary(id: ID): Boolean @function(name: "startItineraryFn-${env}")
}

type Query {
  getDevicePosition(id: ID!, history: Boolean): [Coords]
    @function(name: "getDevicePositionFn-${env}")
}

Step 5: Push resources to the cloud

Finally, push Route Tracking related resources to the cloud by running amplify push from the root of your project folder.

Note that if the Amplify CLI asks you to generate the schemas/models for the GraphQL API, answer NO. These files are already included in the base application.

After the Amplify CLI has finished deploying the resources, you can once again start the application by running npm start in your terminal.

Now that you’ve implemented the route tracking feature, you can start tracking a simulated vehicle. To start the simulation, you must have an itinerary with the date set as the current date that is also already optimized

Figure 6: Select the start button to simulate and track a vehicle on the map.

Cleanup

To stop recurring charges, you can clean up the entire application by running the following command from the project root folder:

amplify delete

Conclusion

In this post, using a field service and route sales use case, we’ve demonstrated how you can build your own transportation and logistics tracking solution from scratch using Amplify, Amazon Location, AWS AppSync, and AWS IoT. The three well-integrated but modular components of the solution (Route Entry, Route Calculation, and Route Tracking) should provide you with a robust starting point for adapting this solution to your own organization’s route planning and tracking needs.

About the authors:

Andrea Amorosi

Andrea Amorosi is a Senior Partner Solutions Architect at AWS. Andrea has a deep software engineering background. He’s a builder at heart, with a keen interest in serverless computing and developer tools. Andrea is a member of the Builder Experience Technical Field Community at AWS and the creator and maintainer of the official Amazon Location samples repo.

Kanishk Mahajan

Kanishk Mahajan is WW Cross-Service Solutions Architect Leader at AWS. Kanishk specializes in cloud operations, resilience, migrations and modernizations, and security and compliance. He is a Technical Field Community member in each of those domains at AWS.

Mohit Dubey

Mohit Dubey is the head of supply chain solutions business development at AWS. He is responsible for helping define and run the AWS supply chain solutions strategy across industries. Mohit often collaborates with AWS customers to help transform their manufacturing, distribution, consumer, and aftermarket supply chains, using cutting-edge AWS technologies and thought leadership.