Building APIs with Jekyll
This blog post is part of my Advanced Jekyll series. Last week I wrote about using Custom Jekyll Plugins with GitHub Pages which I highly recommend reading when you get a chance.
In many cases, when you’re building websites in Jekyll, those websites become the single source of truth for that information for the outside world (and possibly internally). For example, a careers website would contain all job listings, an events website would have all the events and their state, etc. You get the idea. These are the kind of sites you’d build with Jekyll.
Wouldn’t it be easy (and lots of fun) to expose that data via an endpoint? Surely that’s not possible with Jekyll because static site generators just aren’t capable of that, right?
Well, it is very possible and super simple! And I’m going to show you how you can build an API in Jekyll. 🙂
Create our Jekyll Project
For this tutorial, I am going to use my shell (I use iTerm 2 on macOS) to create a Jekyll website for a “fake” monthly meetup which will list all of our meetups in two formats: on the homepage in HTML and on a separate JSON endpoint.
Run the commands below after
$. If your shell looks just like below, you’re good to head to the next section! For your reference, I use Ruby 2.2.4 for this tutorial.
- Help: How do I install Ruby 2.2.4?
- Help: I’m having trouble installing Jekyll.
- Help: I’m struggling to use Terminal on my Mac.
Let’s Store Our Data
Jekyll Datafiles helps you store data in a central place (in CSV, JSON or YAML) and access said data easily inside of your Jekyll project. Datafiles live in the
_data folder, which we’ll need to create (as it isn’t created by default).
Once we have files created inside of the
_data folder, we can start up our Jekyll serve and access it through the
site.data variable in Liquid.
In this example, I’m going to create a meetup entry for London April 2017.
Now we need to list all of our meetups in
index.md in the root of our project:
Pretty cool. Now if we create any other files in our
_data folder they will automatically show up on our homepage if they are formatted similarly to our
However, what if in the future we want to store other data in our meetup website, like a list of all the talks that were given, etc? That’s not possible because all of the information stored in
_data is just a list of our meetups. So we’ll need to restructure our data to serve that purpose.
- Help: What is YAML?
- Help: I still don’t understand Jekyll Datafiles.
- Help: I still don’t understand what Liquid is.
- Extra reading: The GitHub website for Liquid’s templating language
Structuring our data
With Jekyll Datafiles, you can store your data is any number of folders/files in the
_data folder. So, in essence, we can store our meetups in
_data/meetups and problem solved, right?
However, I’d go a step further and create a more nesting for our meetup data. So, we can have a folder called
meetups/ then one for the year, month and have all relevant meetups in that particular folder? Sounds good.
Great! However, in this project, we don’t actually care about the filename is called. This hierarchy is just for our benefit, Jekyll is fine with it either way. Now, it makes no sense to repeat ourselves, so we can cut the month
2017 and the word
meetup from our
.yml filename so let’s do that.
Now that folder structure is looking a lot more fun to work with. However,
index.md will no longer any of our meetups. This is because
site.data will now be a multi-dimensional hash (a hash inside of a hash) based on our folder structure. You can see what I mean later in the article when we try to create our API endpoint.
This means we’ll need to rename
site.data.meetups.2017.04 in our
index.md, which seems quite odd, right? It would only show all of our meetups in April.
So, we’ll need to write multiple nested
for-loop statements in our
index.md in order to show all of our meetups, not just those specific a year or month. Let’s do that below:
The above code runs a
for-loop for each folder structure we have. As you can see, we have three folders in
_data (which are
:month) and we have a
for-loop statement for each level of hierarchy. That’s great. However, this is really ugly code. We need to simplify this logic, which I’ll do later.
Creating our API endpoint
That’s it, we have a JSON endpoint that lives at
/meetups.json in our site!
So, what does that exactly output? See below.
That’s fairly nice, right? This could be published right now and it’ll work just fine. But it’s time to add some polish to make it look 💯!
- Help: I still don’t get what an API actually is.
- Help: What is YAML?
- Help: What is the difference between YAML and YAML Front Matter?
Writing A Jekyll Plugin To Polish Our API
We’ll need multiple custom filters for a consistent, well structured API:
- Having all of our events as one array instead of a nested hash.
- Being able to filter what columns are accessible in our API
- Being able to wrap our API in a easy-to-follow format
So, I’ve gone ahead and wrote a custom Jekyll filter called
ApiFilter that I’ll go ahead and save in
_plugins/filters/api_filter.rb that’ll implement these rules:
Now, if we’re running a Jekyll server, we’ll need to restart that server for our plugin to work. Jekyll is smart enough to know that we’ve added a plugin and will autoload it upon running
$ jekyll serve.
Let’s apply these filters to our
meetups.json file in our Jekyll project:
And the JSON output over at
/meetups.json on our site will now be:
Pretty cool, right? Our data looks different and a lot more predictable now:
- It is a flat array that is wrapped around the
- We chose not to show
venuewhich is no longer exposed
- It shows us when the file was
last_updatedwhich is helpful
P.S. We can now go back to our
index.md and make that look pretty:
The power of code, right? I love it - things are just so simple!
Renaming the API endpoint
I’m just about ready to publish my API endpoint, but I’m not particularly happy about the location of the endpoint. It’s on the root of my website and it’s called
meetups.json. I’d like for it to be in an
Technically, I could just create a folder called
api/ in my Jekyll project and move my
meetups.json into that folder. That’ll work just fine. But there’s an easier way if we just add the following line to the top of our
Amazing. We now have an automatically generating API, in a structure we like and at a URL endpoint that we like. There’s a lot more we can do here, but this is a great starting point.
- Extra reading: More information on Jekyll Permalinks
I would love to see more companies use the power of Jekyll across their websites. Like many other developers, I love playing around with data and I’d recommend looking into building JSON endpoints even in your static sites. It’ll probably help your own developers a bunch, too.
- Extra reading: All of this code is in a single GitHub Gist!
- Extra reading: Check out my personal API. It’s built on Jekyll!
Have any questions? Feel free to reach out - I would love to hear from you! 🙃