Easy Lambda with Gatsby and Netlify Functions

Let’s look at how to use Netlify Functions in Gatsby. Why do we want to do this? Gatsby is a static site generator, which is excellent for many reasons, one of which is that no server is required making it easy to host and lightning-fast to run. Netlify Functions gives us a way to serve up dynamic content to Gatsby. If you are sold on this idea, then let’s build two functions: 1) a straightforward Hello World example and 2) A more complex example that makes a call to a REST API. Let’s get started.

Create a Gatsby starter app.

If you have not installed the Gatsby CLI, nows the time

npm install -g gatsby-cli

Now let’s use it to create our starter app.

gatsby new gatsby-netlify-function https://github.com/gatsbyjs/gatsby-starter-hello-world

Let’s test our new application.

cd gatsby-netlify-function
gatsby develop

Open a browser to http://localhost:8000

Add Hello World Function Example

Now let’s get to the reason why we are here, to build a function. First, we need to install dependencies.

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

The Run Script needs to be modified. Open package.json and replace the scripts section with this.

"scripts": {
  "develop": "gatsby develop",
  "start": "run-p start:**",
  "start:app": "npm run develop",
  "start:lambda": "netlify-lambda serve src/functions",
  "build": "gatsby build && netlify-lambda build src/functions",
  "build:app": "gatsby build",
  "build:lambda": "netlify-lambda build src/functions",
},

Next we need to tell Netlify about our function. We do this in the netlify.toml file in the project root. Add this section.

[build]
command = "npm run build"
functions = "functions"
publish = "public"

Write our Hello World Function in a file /src/functions/hello.js.

export function handler(event, context, callback) {
  console.log('queryStringParameters', event.queryStringParameters)
  callback(null, {
    // return null to show no errors
    statusCode: 200, // http status code
    body: JSON.stringify({
      msg: 'Hello, World! ' + Math.round(Math.random() * 10),
    }),
  })
}

That’s all we need to run Functions on Netlify. But wait, I want to test this locally. To run locally, we need to add a proxy export in gatsby-config.js. Edit the file to include the following export.

const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = {
  developMiddleware: (app) => {
    app.use(
      '/.netlify/functions/',
      createProxyMiddleware({
        target: 'http://localhost:9000',
        pathRewrite: { '/.netlify/functions/': '' },
      })
    )
  },
}

Now we can add the Hello World Function to index.js.

import React, { useState } from 'react'

const IndexPage = () => {
  const [functionMessage, setFunctionMessage] = useState('')
  const callHelloFunction = () => {
    setFunctionMessage('loading …')
    fetch('/.netlify/functions/hello')
      .then((response) => response.json())
      .then((data) => setFunctionMessage(data.msg))
  }
  return (
    <div>
      <h1>Netlify Function.</h1>
      <button type='button' onClick={callHelloFunction}>
        Run Hello Function
      </button>
      <p>Result: {functionMessage}</p>
      <button type='button' onClick={callUsersFunction}>
        Run Users Function
      </button>
      <Users users={users} />
    </div>
  )
}

export default IndexPage

Finally, we can run the demo. Open a terminal to the project root and run this command.

npm run start:lambda

Open another terminal to the project root and run this command.

gatsby develop

Open a browser to http://localhost:8000.

Add REST Function Example

That was great, now let’s try something more interesting. Let’s use the Random User API to grab a list of users. You might want to do something like this as a proxy to avoid CORS issues or submit a form or access protected resources.

Create a new Function in /src/function/users.js.

import fetch from 'node-fetch'

exports.handler = async function(event, context) {
  const headers = {
    Accept: 'application/jsonhtml',
  }

  try {
    const response = await fetch('https://randomuser.me/api/?results=3', {
      headers,
    })
    if (!response.ok) {
      return { statusCode: response.status, body: response.statusText }
    }
    const data = await response.json()
    return {
      statusCode: 200,
      body: JSON.stringify(data),
    }
  } catch (err) {
    console.log(err) // output to netlify function log
    return {
      statusCode: 500,
      body: JSON.stringify({ msg: err.message }), // Could be a custom message or object i.e. JSON.stringify(err)
    }
  }
}

Now we edit /src/pages/index.js to call and show the results from the Function.

import React, { useState } from 'react'

const Users = ({ users }) => {
  const hasUsers = users && users.length > 0
  if (hasUsers) {
    const userRows = users.map((user) => (
      <tr>
        <td>
          <img src={user.picture.thumbnail} alt='thumbnail' />
        </td>
        <td>{user.name.first}</td>
        <td>{user.name.last}</td>
      </tr>
    ))
    return (
      <table>
        <tr>
          <th></th>
          <th>Firstname</th>
          <th>Lastname</th>
        </tr>
        {userRows}
      </table>
    )
  }
  return <div>Lookup users</div>
}
const IndexPage = () => {
  const [functionMessage, setFunctionMessage] = useState('')
  const callHelloFunction = () => {
    setFunctionMessage('loading ...')
    fetch('/.netlify/functions/hello')
      .then((response) => response.json())
      .then((data) => setFunctionMessage(data.msg))
  }
  const [users, setUsers] = useState([])
  const callUsersFunction = () => {
    setUsers([])
    fetch('/.netlify/functions/users')
      .then((response) => response.json())
      .then((data) => setUsers(data.results))
  }
  return (
    <div>
      <h1>Netlify Function.</h1>
      <button type='button' onClick={callHelloFunction}>
        Run Hello Function
      </button>
      <p>Result: {functionMessage}</p>
      <button type='button' onClick={callUsersFunction}>
        Run Users Function
      </button>
      <Users users={users} />
    </div>
  )
}

export default IndexPage

All that’s left to do is to run it as we did before. Open a terminal to the project root and run this command.

npm run start:lambda


Open another terminal to the project root and run this command.

gatsby develop

Open a browser tohttp://localhost:8000.

Deploy to Netlify

Commit the code to GitLab or GitHub then log into Netlify at https://www.netlify.com/. Click the ‘New Site from Git’ button in the upper right of the Sites tab and select your git repository. Accept the defaults, and your application will be running in a minute.

Source code:https://gitlab.com/jameskolean/gatsby-netlify-function/-/tree/master


Copyright © 2020 Code Green LLC