Adding serverless APIs to Gatsby projects in Vercel

October 31, 2020

Approximately 3 minute read time.

Hey everyone! It’s been a solid two weeks since I’ve actually written a blog. I’ve been feeling really under the weather, so I’ve been mostly taking the last few weeks easy (don’t worry, it wasn’t/isn’t COVID). That, and Pokemon Crown Tundra got released, so I’ve been playing a lot of that lately, but it feels nice to be back to writing some blogs!

In the blog I wrote about how I created my blog, I briefly mentioned that one of the reasons that I didn’t need to use Next.js for this site was because of the fact that it offered more functionality than I needed. All the pages on this site are built statically, and Next.js can do that too, but it also has great support for dynamic routes and APIs.

I’m not convinced that this point that I’ll ever need dynamic routing built into this site since it’s using Gatsby. However, I might want to create APIs later for mailing lists, forms, etc. If I ever do need those APIs, Vercel actually makes it really easy to add APIs to any project.

Originally this post was going to be about how easy making microservice APIs is using micro, but then I discovered that micro was designed to be ran within a container, and that Vercel has better support for adding APIs to any Node project using it’s Serverless Helper Functions.

Adding an API

Adding serverless APIs to Vercel projects is dead simple. You can review the link above and find some instructions. What I’ve done on this site is I’ve deployed the example shown in the link to a route on my website at api/examples/hello-world. For posterity, the code just looks like this:

module.exports = (req, resp) => {
  const { name = "World" } = req.query;
  resp.json(`Hello ${name}!`);
};

This is a fairly straight-forward function: it accepts two objects, one representing the request, which contains all the query parameters and any applicable bodies, and then an object we can use to send the response with.

I added this route by simply creating an api folder at the root of my project. Vercel will build out serverless API routes using the file structure defined within the api folder, and will serve any .js, .go, .py, or .rb files defined within as serverless lambda functions.

Consuming in Gatsby

I was really hoping to consume the API directly from this blog post, but I’m not using mdx for my posts quite yet, and injecting JavaScript in-line on a markdown file didn’t really seem like a very safe thing to try and do, nor did I think it was feasible. SO, instead, I created an example page of how a Gatsby page might consume a serverless function.

You can view the demo here, but I’ll talk more about the code here. You might consider opening the demo page up on another tab.

In order to get the query parameters, Gatsby passes in location data to each of it’s pages. We can use this, along with the fetch API to grab the query params, can call our serverless function with the parameters:

import React, { useEffect, useState } from 'react'
import { Link } from "gatsby"
import Layout from "../../components/layout"
import SEO from "../../components/seo"
import queryString from "query-string"

export default ({location}) => {
  const { search } = location
  const { name = "World" } = queryString.parse(search)
  const [ greeting, setGreeting ] = useState('Loading...')

  useEffect(() => {
    fetch(`/api/examples/hello-world?name=${name}`)
      .then(resp => resp.json())
      .then(greet => setGreeting(greet))
  }, [name])

  return (
    <Layout>
      <SEO title={`Hello ${name}`}/>
      <section className="hero is-white is-large">
        <div className="hero-body">
          <h1 className="title">{greeting}</h1>
        </div>
      </section>
      <section>
        If you stumbled upon this page not knowing what it was, go <Link to={`/adding-serverless-apis-to-gatsby-projects-in-vercel`}> here.</Link>
      </section>
    </Layout>
  )
}

We’re able to use fetch to call an API using query parameters that were read from location data, and then render that data client-side once the server responds! Neato!

The one thing you might notice when loading the page is that while the page rendering is pretty quick, there’s a bit of a delay in loading the actual information from the serverless function created by Vercel, hence our page says “Loading…” first before getting the actual greeting. I will say that this is one thing that Next.js does pretty well that Gatsby does not: all pages in Gatsby are static, whereas Next.js can actually create lambdas of pages, so the loading and rendering of the data is handled server-side. If we were using Next.js, we could use it’s getServerSideProps API to render everything server-side so that the client doesn’t have to load any data itself. No need for loading indicators.

Conclusion

Hopefully you’ve found some of this information useful! As always, links to my social media are located below if you want to ask questions about this post or if you want to suggest a future post. Thanks for reading!