Querying Random Blog Posts with Netlify Functions

Wednesday, December 4th 2019

Inspired by something Derek Sivers implemented on his site, I decided to add a URL to this site that automatically redirects to a random blog post. You can find the link via the /dev/random menu item or simply go to george.mand.is/random.

I like it because it adds a quality that's tricky to capture on the web: "skimmability." It reminds me of being able to thumb through the pages of a book before committing.

With a Traditional Server Setup

Setting this up on a traditional server would've been fairly straightforward. If it was running on Apache or NGINX for example it probably would've been just a matter of adding a line to the configuration file to redirect requests to another script on the server that could pick a blog post at random and tell the browser to redirect. There would be other implementation details, but that's the gist of it.

With Netlify

This site, however, is hosted on Netlify. In all the ways Netlify eases the development and deployment experience for some types of sites, doing relatively simple backend things often requires finding interesting workarounds.

For this random URL redirection idea I was able to get this up and running without too much trouble using Netlify Functions.

Here are the steps to take:

Install the Netlify Command Line Tool.

This will allow you to setup and test your functions locally. You can find more information on the documentation site on how to configure your project locally and connect it to one of your Netlify sites.

Once you've successfully installed the command line tools and connected your local working folder to your site you can run npm run dev in the console and access your site at localhost:8888 in the browser. Functions, redirects and other Netlify-specific features will behave just as though they're in production on Netlify's servers and allow us to test this feature as we're building it.

Setup Netlify functions.

I suggest calling the folder functions and configuring it via a netlify.toml file instead of using the web interface. There is more informatoin about how to set that up on Netlify's documentation page about configuring functions.

Setup Your Redirect

Create a _redirects file in your Netlify site and add this line:

  /random /.netlify/functions/random 302

You can also set this up in your netlify.toml file, which is explained in this blog post. My site has a lot of simple redirects though and I find the separation to be more manageable.

Selecting a Random URL From Your Blog

We'll need a way to have all the URLs available in our function. This is the trickier part and will vary depending on how you built your site. There are many approaches, but this was my approach:

  • Create a special URL that returns a JSON feed that's nothing but URLs for all my blog posts
  • Use node-fetch in my function to pull in that data and pick one at random
  • Send information in the header response to tell the browser to perform a 302 redirect to the random selection

I debated adding some measuer of security to this special URL, but decided it didn't much matter. It's really no different than a sitemap and I've ensured that only blog post URLs are presented in this feed. You can see it here:

george.mand.is/_all.json.

You'll notice it's returning relative URLs. This is helpful for testing it locally.

I found creating this feed fairly straightforward with Eleventy but you could probably do this with whatever static generator you're using. If you're using Jekyll I'd taking a look at my Jekyll JSON feed templates on GitHub.

Creating the Function

Last but not least we need to create the actual function! I've written mine in Node.js, but you could write yours in Go as well.

It's worth noting that the directory structure influences the URL structure for your Netlify function. I've saved the file that contains my function at functions/random.js in my project folder. This function's endpoint is automatically created at /.netlify/functions/random both in production and locally.

Here is the code:

/**
 * Random Blog Post (/random)
 * ===
 * George Mandis (george.mand.is)
 */

require("dotenv").config();
const fetch = require("node-fetch");

exports.handler = function(event, context, callback) {
  fetch(`${process.env.URL}/_all.json`, { headers: { "Accept": "application/json" } })
    .then(res => res.json())
    .then(response => {
      const randomPost =
        response.posts[Math.round(Math.random() * response.posts.length - 1)];

      callback(null, {
        statusCode: 302,        
        body: `Location:${process.env.URL}${randomPost}`,
        headers: {
          "Location": `${process.env.URL}${randomPost}`          
        }
      });

    });
};

If you've completed all of these steps you should be able to test your redirection URL locally at localhost:8888/random and see a random blog post returned!

So far I really enjoy this feature. Anecdotally I'm noticing a few more hits on older posts than normal, but it's nice even for my own sake. It's fun to be able to flip back through the posts I've written over the years.