Building a REST API from Google Sheets with AWS Lambda and API Gateway

I recently came across a Facebook group in Brighton which acts as a community for local businesses who are delivering locally during the Coronavirus crisis. All of the data was aggregated on a Google Sheet - massive credit to the moderators for collecting and creating the data. I’d recently been experimenting with Svelte and Sapper at work and thought I’d spend the weekend building a small microsite using data from the spreadsheet.

This was the result: brightonquarantine.co.uk

This article is a guide to build the API used by the front-end of the website. All of the code can be found in this repository.

Prequisites

  • Ensure you have a spreadsheet of data set up with the first row being labels for your columns
  • Have an AWS account

Integrating the Google API

Let’s start by getting the data from Google sheets. For the time being, we’re going to get the data outputting in the terminal (we’ll do the Lambda integration later).

Create a new project

Firstly make a new directory, cd to it and run:

npm init

Fill out the information as prompted, ignoring anything you don’t need to fill out. Then run:

npm install google-spreadsheet

This will fetch the code from this repository.

Authenticate the request

In your browser:

  • Head over to the Google Developers Console and create a new project
  • Now go to Enable APIs and Services and enable the Google Drive API
  • Now navigate to Create Credentials:
    • Select Google Drive API from Which API are you using?
    • Select Web server from Where will you be calling the API from
    • Select Application data from What data will you be accessing?
    • Select No for the API with App Engine question
    • Create some credentials (setting the Role as Editor)
    • Ensure JSON is selected

The above steps should prompt a download of a JSON file. Rename this file to client_secret.json and put it in the directory we created above.

Create a new file in this spreadsheet called index.js and open this file in your IDE.

Open your client_secret.json file and copy the email address (without the quotation marks) next to client_email.

Go to the spreadsheet you originally created and share it with this email address.

Making our first request

Head back over to the browser and fetch the ID of the spreadsheet from the URL.

In index.js paste the following (including the string of the spreadsheet ID when we instantiate GoogleSpreadsheet):

// Get spreadsheet npm package
const { GoogleSpreadsheet } = require('google-spreadsheet');
// Ensure you've updated this file with your client secret
const clientSecret = require('./client_secret.json');

// Add your Google sheet ID here
const googleSheetID = '';

// Instantiates the spreadsheet
const sheet = new GoogleSpreadsheet(googleSheetID);

// Asynchronously get the data
async function getData() {
    try {
        // Authenticate using the JSON file we set up earlier
        await sheet.useServiceAccountAuth(clientSecret);
        await sheet.loadInfo();

        // Get the first tab's data
        const tab = sheet.sheetsByIndex[0];

        console.log(tab.title);

    } catch(err) {
        console.log(err);
        return false;
    }
}

// Call the above method
getData();

In your terminal, from the directory you’re working in, run:

node index.js

If everything has been set up correctly you should see the title of your sheet’s first tab.

Get row data

We’re now going to fetch some row data. Replace the getData method with this one:

// Asynchronously get the data
async function getData() {
    try {
        // Authenticate using the JSON file we set up earlier
        await sheet.useServiceAccountAuth(clientSecret);
        await sheet.loadInfo();

        // Get the first tab's data
        const tab = sheet.sheetsByIndex[0];

        // Get row data
        const rows = await tab.getRows();

        // Empty array for our data
        let data = [];

        // If we have data
        if (rows.length > 0) {
            // Iterate through the array of rows
            // and push the clean data from your spreadsheet
            rows.forEach(row => {
                data.push(row['Name']);
            });
        } else {
            return false;
        }

        console.log(data);

        // Return the data JSON encoded
        return JSON.stringify(data);
    } catch(err) {
        console.log(err);
        return false;
    }
}

This should log out all of the data in the Name column of your spreadsheet.

Clean up data

We’ll add one more method to clean up our data. Depending on your column names, you’ll need to alter this method to return everything you need from your spreadsheet. Above the getData method, add this method in:

// Add the data we want into an object
function cleanData(data) {
	return {
		name: data['Name'],
		phone: data['Phone Number'],
		website: data['Website']
	}
}

Inside the getData method replace the current data.push line to this:

data.push(cleanData(row));

Run the script again and you should see an array of objects.

Remove any console.log and we’re ready to move onto the next step.

Lambda time

Now that we’ve got the Google API working let’s make our Lambda. Login to your AWS account and follow these steps to create a test Lambda function.

Once you’ve run Test and it’s all working, let’s add our code:

  • ZIP the directory we’ve been working in
  • In the Lambda project, select Upload a .zip file under Code entry type and upload the ZIP we just created
  • Make sure you move all of the files from this directory into the parent folder

We’re going to need to make a few minor modifications to the script to make it compatible with Lambda. Firstly, in the inline editor, delete the call to getData and replace it with the following:

exports.handler = async (event) => {
    const data = await getData();
    
    let response = {
        "statusCode": 200,
        "body": data,
        "isBase64Encoded": false
    };

    if (!data) {
        response = {
            "statusCode": 400,
            "body": 'Something went wrong',
            "isBase64Encoded": false
        };
    }

    return response;
}

Click Test and you should see all of the data logged out.

API Gateway

Now that our Lambda is working we’ll need to set up an API we can call to run it.

Navigate to API Gateway and follow the steps listed under Create a “Hello World” API here. Synching up your Lambda and choosing a meaningful name.

You now should have a URL we can run GET requests on.

Wrapping up

Now that we have our Lambda synced up to API gateway we’re ready to start making requests to it on the front-end of the site.

Find the git repository with this sample code here.