by Gerard Sans |  @gerardsans

Building a

serverless geolocation API

Building a

serverless geolocation API

SANS

GERARD

Developer Advocate AWS

Developer Advocate AWS

International Speaker

Spoken at 143 events in 37 countries

Bike Sharing

Benefits

  • Transport flexibility
  • Reduce traffic emissions
  • Reduce traffic congestion
  • Health benefits for users

Santander Cycles

Overview

  • Since 2010
  • +12,000 Bikes
  • 778 stations

Boris Bikes

LNDBikes

Fullstack Serverless

🦄

🌩️

Icons made by Gregor Cresnar from www.flaticon.com is licensed by CC 3.0 BY
Icons made by Darius Dan from www.flaticon.com is licensed by CC 3.0 BY

No servers to manage

Fault tolerance High availability

background Layer 1

Never pay for idle usage

Auto-scales immediately

Serverless

$

AWS AMPLIFY

Categories

interactions

storage

notifications

auth

analytics

function

amplify add <category>

api

hosting

xr

AWS-AppSync_light-bg
Amazon-Pinpoint_light-bg
Amazon-S3_light-bg
AR-VR_light-bg
Amazon-Cognito_light-bg
Amazon-Lex_light-bg
Amazon-Kinesis_light-bg
AWS-Lambda_light-bg
Amazon-CloudFront_light-bg

transcribe

rekognition

translate

comprehend

amplify add predictions

polly

London

Unified API

/BikePoint

/BikePoint/id

TfL Unified API

/BikePoint/Search

[
  {
    "id": "BikePoints_1",
    "commonName": "River Street , Clerkenwell",
    "additionalProperties": [{
      "key": "NbBikes", "value": "11",
     }],
    "lat": 51.529163,
    "lon": -0.10997
  }
  // 777 more
]

/BikePoint

{
  "id": "BikePoints_1",
  "commonName": "River Street , Clerkenwell",
  "additionalProperties": [{
    "key": "NbBikes", "value": "11",
  }],
  "lat": 51.529163,
  "lon": -0.10997
}

/BikePoint/BikePoints_1

Loading   bike stations

Data Transformations

GeoJSONfeature

BikesPoint

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [-0.10997, 51.529163]
  },
  "properties": {
    "id": "BikePoints_1",
    "name": "River Street , Clerkenwell"
  }
}

geoJSON feature

Coordinates = [-0.10997, 51.529163]

51.529163

-0.10997

Coordinates

Data Transformations

GeoJSONfeature

BikesPoint

mapbox Source

mapbox Layer

REST API integration

type BikePoint @model {
  id: ID!
  name: String!
  description: String
  location: Location
  bikes: Int
}

GraphQL Schema

// request VTL template
{
  "version": "2018-05-29",
  "method": "GET",
  "resourcePath": "/BikePoint/$context.source.id",
}

BikePoint.bikes HTTP Resolver

// response VTL template
#set($body = $util.parseJson($ctx.result.body))
#if($ctx.error)
  $util.error($ctx.error.message, $ctx.error.type)
#end
#if($ctx.result.statusCode == 200)
  $body.additionalProperties[6].value
#else
  #return
#end

BikePoint.bikes HTTP Resolver

Adding Search

type BikePoint @model @searchable {
  id: ID!
  name: String!
  description: String
  location: Location
  bikes: Int
}
type Location {
  lat: Float
  lon: Float
}
type Query {
  nearbyBikeStations(location: LocationInput!, m: Int, limit: Int)
}

GraphQL Schema

Data Transformations

GeoJSONfeature

BikesPoint

GraphQL API

Elastic Search

# Create index
PUT /bikepoint

# Setup location type as geo_point
PUT /bikepoint/_mapping/doc
{
  "properties": {
    "location": {
      "type": "geo_point"
    }
  }
}

Elastic Search index

mutation addBikePoint {
  createBikePoint(input: { 
    id: "BikePoints_1" 
    name: "River Street , Clerkenwell" 
    location: { 
      lat: 51.529163 
      lon: -0.10997 
    } 
  }) { id }
}

Automatic indexing

GET /bikepoint/doc/_search
{ 
  "query": {
    "bool" : {
      "must" : { "match_all" : {} },
      "filter" : {
        "geo_distance" : {
          "distance" : "500m",
          "distance_type": "arc", 
          "location" : {
            "lon": -0.134167, "lat": 51.510239
          }

Query nearbyBikeStations (1/2)

  "sort": [{
    "_geo_distance": {
      "location": {
        "lon": -0.134167, "lat": 51.510239
      },
      "order": "asc",
      "unit": "m",
      "distance_type": "arc"
    }
  }]
}

Query nearbyBikeStations (2/2)

Distance Calculations

[lon1, lat1]

[lon2, lat2]

Haversine Formula

Great-circle distance

Distance Calculations

double distance(double lat1, double lon1, double lat2, double lon2) {
  return 6378137 * haversine(lat1, lon1, lat2, lon2);
}

double haversine(double lat1, double lon1, double lat2, double lon2) {
  double hsinX = Math.sin((lon1 - lon2) * 0.5);
  double hsinY = Math.sin((lat1 - lat2) * 0.5);
  double h = hsinY * hsinY + (Math.cos(lat1) * Math.cos(lat2) * hsinX * hsinX);
  return 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h));
}

ElasticSearch arc distance (WGS 84)

More

@undef_obj

@kurtiskemple

@dabit3

Kurt Kemple

Richardo

Nader Dabit

@TheSwaminator 

Nikhil Swaminathan

Building a Serverless Geolocation Search API Using GraphQL

By Gerard Sans

Building a Serverless Geolocation Search API Using GraphQL

In this talk, we will be using AWS AppSync & Elasticsearch to create a geolocation search service API that will allow users to search within a distance from a given location and display results in a map. We will start designing our schema to introduce the geolocation data, implementing resolvers while discussing best practices and architecture decisions for the presented solution.

  • 2,821