3

I'm building a simple application using vanilla JS in which I retrieve the user's location and pass down the coordinates to Google's Geolocation API. I'm trying to gain access to the API key by setting it as an environment variable through Netlify's UI and I don't quite understand exactly how to implement lambda functions to accomplish the task.

I have a function that gets the user's latitude/longitude and fetches the data from the geolocation API before displaying it in the DOM. As of now I only have an index.html and app.js file.

getUserLocation();

function getUserLocation() {
  async function success(position) {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;
    const geoAPI = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${apiKey}`;

    const { city, state, country } = await getGeoData(geoAPI);

    updateWidget({ city, state, country });
  }

  function error() {
    alert("Unable to retrieve your location");
  }

  if (!navigator.geolocation) {
    console.log("Geolocation is not supported by your browser");
  } else {
    navigator.geolocation.getCurrentPosition(success, error);
  }
}

I tried reading Netlify's documentation but I'm not sure how to implement the solution to my simple project. Any help is much appreciated!

1 Answer 1

3

Since the key is a secret key, we will be creating a Netlify function to make the api call to https://maps.googleapis.com/maps/api/geocode/json and the endpoint will be /.netlify/functions/location on our site.

For this example, we will not be creating a build bundle using node tools, so we will include our dependency module node-fetch with our function.

Add the secret api key on the Netlify admin console

Add the secret api key to environment variables on your site in a variable MAP_GOOGLEAPIS_KEY

Repository project structure

enter image description here

netlify.toml file (build config):

We are not actually doing any builds, but this will help us to configure our deploy container on Netlify to know where our functions are located.

[build]
  functions = "functions"
  publish = "site"
  command = "echo 'No build here yet!'"

The functions/location/location.jsfunction code

const fetch = require('node-fetch');

const apiKey = process.env.MAP_GOOGLEAPIS_KEY;

exports.handler = async function(event, context) {
  try {
    const { latitude, longitude } = event.queryStringParameters || {};
    if (!latitude || !longitude) {
      return { statusCode: 400, body: "Missing query parameters" };
    }
    const uri = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}`;

    const response = await fetch(`${uri}&key=${apiKey}`);
    if (!response.ok) {
      // NOT res.status >= 200 && res.status < 300
      return { statusCode: response.status, body: response.statusText };
    }

    const data = await response.json();

    return {
      statusCode: 200,
      headers: { "content-type": "application/json" },
      body: JSON.stringify(data)
    };
  } catch (err) {
    console.log("invocation error:", err); // output to netlify function log
    return {
      statusCode: 500,
      body: err.message // Could be a custom message or object i.e. JSON.stringify(err)
    };
  }
};

New endpoint call for our client side script

No secret key on the client!

function getUserLocation() {
  async function success(position) {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;
    const geoAPI = `/.netlify/functions/location?latitude=${latitude}&longitude=${longitude}`;
Sign up to request clarification or add additional context in comments.

5 Comments

This is incredibly helpful, thank you! This might be a silly question, but where should I put my package-lock.json and package.json files?
Also, how would having more than one handler affect where I place the node_modules folder? I noticed you placed it in the location folder but what if I had another folder containing a different function?
Q1 package.json file goes in your root of the project if you need a build process. Q2 This is an example of a non-bundled function, so you need to treat your functions as bundles by placing them in their own directory with their required deps. If you use a functions src location and bundle the functions with a package manager like webpack or using netlify-lambda, you can just put the script in the /functions folder as the name of the function. Also, if they do not have any external deps, you can just put the function directly in the functions directory and Netlify will zip-it-and-ship-it.
Rookie question but does this answer use Node? I am building a vanilla JS app and trying to hide API secretes but don't understand the node-fetch part. Is that just running on Netlify which already has node?
Joshua This example is a Netlify function which is essentially an AWS Lambda function, so yes in this case it is using Node on a server with the API secrets as environment variables that would be hidden from anyone using the api endpoint. The only thing returned to the client (user) is the data returned by the api call.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.