Skip to main content
Documentation Configuration Plugins

HTTP Requests and the Resource Builder

In this section, you’ll learn how to make web requests and easily parse the response to save site data or construct new resources like blog posts or collection entries.

Below is an example of making an HTTP GET request to a remote API, looping through an array parsed from the JSON response, and saving new posts based on each item.

The examples on this page use the HTTPX Ruby gem, but you can use any HTTP client. If you use a gem, just remember to run bundle add httpx (or your preferred gem) so that you can require it.

require "httpx"

class LoadPostsFromAPI < SiteBuilder
  def build
    HTTPX.get("https://domain.com/posts.json").json.each do |post|
      add_resource :posts, "#{post["slug"]}.md" do
        ___ post
        layout :post
        categories post["taxonomy"]["category"].map { |category| category["slug"] }
        date Bridgetown::Utils.parse_date(post["date"])
        content post["body"]
      end
    end
  end
end

Table of Contents #

The Resource Builder #

Adding content from an API to the site.data object is certainly useful, but an even more powerful feature is the Resource Builder. Call the add_resource method to generate resources which function in exactly the same way as if those files were already stored in your repository. It uses a special DSL, similar to Ruby Front Matter.

Here’s an example of creating a new blog post:

def build
  add_resource :posts, "2020-05-17-way-to-go-bridgetown.md" do
    layout :post
    title "Way to Go, Bridgetown!"
    author "rlstevenson"
    content "It's pretty _nifty_ that you can add **new blog posts** this way."
  end
end

This is the programmatic equivalent of saving a new file src/_posts/2020-05-17-way-to-go-bridgetown.md with the following contents:

---
title: Way to Go, Bridgetown!
author: rlstevenson
---

It's pretty _nifty_ that you can add **new blog posts** this way.

Collections #

You can save a resource in any collection:

add_resource :authors, "rlstevenson.md" do
  name "Robert Louis Stevenson"
  born 1850
  nationality "Scottish"
end

You don’t even need to use a collection that’s previously been configured in initializers.rb or bridgetown.config.yml. You can make up new collections and use existing layouts to place your content within the appropriate templates, assuming the expected front matter is compatible.

add_resource :blogish, "fake-blog-post.html" do
  layout :post
  title "I'm a blog post…sort of"
  date "2020-05-17"
  content "<p>I might look like a blog post, but I'm <em>not!</em></p>"
end

That resource would then get written out to the /blogish/fake-blog-post/ URL.

Another aspect of the Resource Builder to keep in mind is that content is a “special” variable. Everything except content is considered front matter, and content is everything you’d add to a file after the front matter.

If you’d like to customize the permalink of a new resource, you can specifically set the permalink front matter variable:

add_resource :posts, "blog-post.md" do
  title "Strange Paths"
  date "2019-07-23"
  permalink "/path/to/the/:slug/"
  content "…"
end

The post would then be accessible via /path/to/the/blog-post/.

Merging Hashes Directly into Front Matter #

If you have a hash of variables you’d like to merge into a resource’s front matter, you can use the ___ method.

vars = {
  title: "I'm a Draft",
  categories: ["category1", "category2"],
  published: false
}

add_resource :posts, "post.html" do
  ___ vars
end

This is great when you have data coming in from external APIs and you’d like to inject all of that data into the front matter with a single method call.

Bear in mind that this doesn’t include your content variable. So you’ll still need to set that separately when using the ___ method, for example:

data = HTTPX.get(article_url).json
add_resource :pages, "articles/#{data["slug"]}.html" do
  ___ data
  content data["body"]
end

DSL Scope #

If you’re not familiar with Ruby DSLs, you may run into an issue where you need to call a method from your builder plugin within add_resource and it’s not in scope. For example, this won’t work:

def string_value
  "I'm a string!"
end

def build
  add_resource :pages, "page.html" do
    title string_value
    content "Page content."
  end
end

The reason it won’t work is because in this example, title is actually interpreted as a method call within the DSL block, which means string_value is a similar call. That would be fine if you’d already added string_value as a front matter key, in which case string_value would return that front matter variable. But in this case, you want to use the string_value method of your plugin.

To accomplish that, provide a lambda using the from: -> { } syntax. Let’s rewrite the above example to work as expected:

def string_value
  "I'm a string!"
end

def build
  add_resource :pages, "page.html" do
    title from: -> { string_value }
    content "Page content."
  end
end

Now the title front matter variable will be set to “I’m a string”.

Builder Lifecycle and Data Files #

Something to bear in mind is that that code in your build method is run as part of the site’s pre_read hook, which means that no data or content in your site repository has yet been loaded at that point. So you can’t, say, build resources based on existing data files as you might assume:

def build
  # THIS WON'T WORK!!!
  site.data[:stuff_from_the_repo].each do |k, v|
    add_resource :stuff, "#{k}.md" do
      ___ v
      content v[:content]
    end
  end
end

Instead, what you can do is define a post_read custom hook and then read in the data:

def build
  hook :site, :post_read do
    site.data[:stuff_from_the_repo].each do |k, v|
      add_resource :stuff, "#{k}.md" do
        ___ v
        content v[:content]
      end
    end
  end
end

Conclusion #

As you’ve seen from these examples, you can use data from external APIs to create new content for your Bridgetown website with the add_resource method provided by the Builder API. While there are numerous benefits to storing content directly in your site repository, Bridgetown gives you the best of both worlds—leaving you to decide where you want your content to live and how you’ll put it to good use as you build your site.

Back to Plugins