DEV Community

Joe Steinbring
Joe Steinbring

Posted on

1

I built my first Cloudflare worker

In the past two years, I have written a few blog posts that explored how to figure out where the user physically is. Most of these experiments involved navigator.geolocation but last week's iOS 15, Private Relay, and Geolocation post brought in the concept of figuring out the person's location based upon their IP address. After finishing that post, I started to wonder what it would take to simplify things. Can I reduce the number of API calls to things and make the result more reliable? In the process, I decided that I would also wrap things up into a central Cloudflare worker.

So, let's see what the guts of the worker look like.

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
function getUrlVars(url) {
var vars = {};
var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
async function handleRequest(request) {
// Is it a get request?
if(request.method == 'GET'){
// Set the latitude
if(typeof getUrlVars(request.url)["latitude"] !== 'undefined'){
latitude = getUrlVars(request.url)["latitude"];
}
else{
latitude = request.cf.latitude;
}
// Set the longitude
if(typeof getUrlVars(request.url)["longitude"] !== 'undefined'){
longitude = getUrlVars(request.url)["longitude"];
}
else{
longitude = request.cf.longitude;
}
}else{
latitude = request.cf.latitude;
longitude = request.cf.longitude;
}
// API Crap
let endpoint = "https://www.mapquestapi.com/geocoding/v1/reverse?key={ MAPQUEST API KEY GOES HERE }&location="+latitude+"%2C"+longitude+"&outFormat=json&thumbMaps=false";
const init = {
headers: {
"content-type": "application/json;charset=UTF-8",
},
}
const response = await fetch(endpoint,init)
const mqContent = await response.json()
// The struct that holds the details of who the user is
let user = {
latitude:latitude,
longitude:longitude,
cfCountry:request.cf.country,
cfCity:request.cf.city,
cfLatitude:request.cf.latitude,
cfLongitude:request.cf.longitude,
cfPostalcode:request.cf.postalCode,
cfRegion:request.cf.region,
cfRegioncode:request.cf.regionCode,
cfTimezone:request.cf.timezone,
mqStreet:mqContent.results[0].locations[0].street,
mqCity:mqContent.results[0].locations[0].adminArea5,
mqState:mqContent.results[0].locations[0].adminArea3,
mqZip:mqContent.results[0].locations[0].postalCode
}
return new Response(JSON.stringify(user, null, 2), {
headers: {
"content-type": "application/json;charset=UTF-8"
}
})
}
view raw index.js hosted with ❤ by GitHub

As you can see above, a lot of the returned data is just things that cloudflare knows about you, out of the gate but in order to get your likely street address, an API call to Mapquest is still needed. I also set it up so that you can pass latitude and longitude values in as get variables. If the user is on an LTE or 5g connection, their location is likely to show up as being in a completely different place.

So, how do we implement this new API?

Using the "Use GPS to update position" and "Use IP to update position" buttons, you can toggle between the two modes of detection. Basically, one passes lat/long coordinates into the API and the other leaves it up to the node script to figure it out.

In a real-world setting, I would execute the IP-based detection by default and give the user the option to use the more accurate option if they wished to do so. This is definitely getting integrated into my Wisconsin State Parks project.

Have any questions, comments, etc? Feel free to drop a comment, below.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs