August 01, 2019

Netlify lambda functions and Gatsby tutorial

gatsbynetlifylambdatutorialJAMstack

Serverless functions...

Static websites don't have a dedicated back-end and server. That's the whole point. However, when you're developing a static website you may find that you could really do with a bit of that back-end functionality. You may want a contact form that automatically sends an email on submission, or a way for a user to subscribe to a mailing list, or perhaps you want to access a private database. You can't do these things on the client-side as its not secure but you don't have a dedicated server to work with!

Enter Netlify Functions!

Netlify functions are essentially AWS Lambda functions and allow you to do these simple tasks away from the client. They're very easy to set-up but combining them with Gatsby can be a little confusing and I found the tutorials available a bit lacking in detail.

Making a basic function.

This tutorial will show you how to set up Netlify Functions on your Gatsby site. I'm not going to go into how to write a useful function, that's a tutorial for another day but I will explain how to get everything set-up and working.

You can do this on an existing Gatbsy website or set-up a new website just to test it if you prefer.

Step 1: Install some useful packages.

Once you have your Gatsby site ready we need to first install some packages as dev dependencies (-D). This means that they're only used in development, not production.

npm install -D http-proxy-middleware netlify-lambda npm-run-all

So what are these for I hear you cry?!

  • http-proxy-middleware
    This creates a nice little proxy for local development and basically just prevents everything from exploding in your dev server.

  • netlify-lambda This allows us to write our function using modern JavaScript etc and it will all be compiled nicely before the build.

  • npm-run-all This is a nice little tool to allow us to run multiple scripts one after the other (or in parallel) automatically.

Step 2: Make the relevant folders.

We're going to need two new folders.

The first is the folder that Netlify will look in to find the functions to run. Netlify wants the finished product once netlify-lambda has transpiled our modern JS so we will tell netlify-lambda to chuck it's finished product in this folder later. I'm going to make a folder called netlifyFunctions for this purpose and put it in the src folder in my Gatsby project. We don't do anything with this folder, it will get filled automatically when we run the dev server or build the project.

The other folder that we need is one for the functions as we write them (e.g. before netlify-lambda gets it's magical mitts on them). This one I'm going to call functions and also put it in the src folder of my project. You can call them whatever you like, I find it easier to see which one is for Netlify and which one is for me!

Step 3: Set-up the proxy for local development.

Just copy and paste this into your gatsby-config.js file to ensure the functions work in development.

// gatsby.config.js

var proxy = require("http-proxy-middleware")

module.exports = {
   // for avoiding CORS while developing Netlify Functions locally
  // read more: https://www.gatsbyjs.org/docs/api-proxy/#advanced-proxying
  developMiddleware: app => {
    app.use(
      "/.netlify/functions/",
      proxy({
        target: "http://localhost:9000",
        pathRewrite: {
          "/.netlify/functions/": "",
        },
      })
    )
  },
  //... plugins etc
}

Step 4: Make some scripts.

I found this step on Gatsby's own tutorial and it really does make life a little easier. As that's what we all strive for I thought I'd include it in the tutorial.

Basically, by adding functions to our project we now need to run two processes. For development we need to run the dev server (gatsby develop) and build the functions (netlify-lambda serve src/functions). We could do this in two terminals but that's a pain and I'm lazy emoji-information_desk_person. So we can use that package we installed to run both these scripts in one!

So go into your package.json file and replace your scripts. I've highlighted the new ones below:

// package.json

"scripts": {
    "develop": "gatsby develop",
    "format": "prettier --write src/**/*.{js,jsx}",
    "serve": "gatsby serve",
    "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"",
    "start": "run-p start:**",    "start:app": "npm run develop",    "start:lambda": "netlify-lambda serve src/functions",    "build": "run-p build:**",    "build:app": "gatsby build",    "build:lambda": "netlify-lambda build src/functions"},

You can see we have two new scripts to run - npm run start and npm run build.

As you can probably guess, start is for development and build is for production. Lets look at 'start' in more detail.

  1. We type npm run start into the terminal.
  2. This runs both the start:app and start:lambda scripts in parallel. The first does our standard gatsby develop and the second runs the functions.

Note: The start/build:lambda script specifies the source folder we made (i.e. the folder we put our functions into). So if you used different folder names you need to adjust these accordingly.

Step 5: Tell Netlify wtf we're doing.

This is all well and good but Netlify doesn't yet have any idea we're throwing functions at it. And it also doesn't know that we've changed the build script we want to use.

So if you don't have one already make a netlify.toml file in your root and add this code to it. Note that we're referencing the folder that we don't touch now not our source folder.

# netlify.toml

[build]
  Command = "npm run build"
  Functions = "src/netlifyFunctions"
  Publish = "public"

Step 6: Write a function!

If you've got this far well done. We're nearly there. The set-up is now complete - we just need to write our function!

Make a JS file in your src/functions folder and name it something sensible that describes the function.

As I said at the beginning of this tutorial - I'm not going to explain how to write a lambda function in this post. So for simplicity's sake we'll make a very basic function that simply returns a string.

// src/functions/hello.js

exports.handler = async (event, context) => {
    return {
      statusCode: 200,
      body: "Hello. Well aren't you a clever clogs."
    };
  };

Step 7: See the fruits of your labour.

We can access this in our Gatsby project by putting this code in a lifecycle method.

componentDidMount() {
        fetch("/.netlify/functions/hello")
        .then(response => response.text())
        .then(console.log)
}

Run the dev server using npm run start and watch the message pop up in the console! Well aren't you a clever clogs indeed!

Alternatively you can go to localhost:9000/hello to see your message.