Bodge.app

Examples

Simple Examples

Hello, World!

return "Hello, World!"

The simplest example. This simply returns "Hello, world!" as plaintext.

If you return just a string, it'll be treated as the body of the response.

Returning JSON

return { hello = "world" }

If you return just a table, it'll be treated as the body of the response, being encoded as JSON automatically.

Setting HTTP Response Headers

return "Ok", {["X-Clacks-Overhead"] = "GNU Terry Pratchett"}

A table returned after any value that can be treated as a body, will be treated as a map of headers to be applied to the response.

Returning HTML

To return HTML, set a content-type header.

return "<h1>Helo, World!</h1>", {["Content-Type"] = "text/html"}

Making an Outgoing HTTP Request

local response = http.request{ url = 'https://httpbin.org/get' }

return response.body

Counter

For each request, this gets the current count from storage, increments it, and writes it back to storage, returning the current count in a json object.

-- get the current count
local count = storage.count or 0
-- increment the count
count = count + 1
-- persist the updated count
storage.count = count

-- log the count
print("count: " .. count)

-- return JSON to the caller
return {count=count}

Note: This example is simplified to show how storage works. It has a race condition if two executions try to update the count at the same time, one can get lost. See the "SVG Hit Counter" example for how to protect against this.

Larger Examples

SVG Hit Counter

This implements a simple hit counter as an SVG image.

lock.acquire("count")
local count = (storage.count or 0) + 1
storage.count = count
lock.release("count")

return string.format([===[
<svg width="200" height="80" xmlns="http://www.w3.org/2000/svg">
  <rect x="0" y="0" width="200" height="80" fill="#222"/>
  <rect x="10" y="10" width="180" height="60" fill="#000"/>
  <text x="100" y="55" font-family="monospace" font-size="40" fill="#00CC00" text-anchor="middle">%06i</text>
</svg>]===], count), {
  ["Content-Type"] = "image/svg+xml"
}
hit count
https://hits.bodge.link/

Parsing an HTML Page

Bodge includes the htmlparser library.

This example fetches the kernel.org homepage and parses out the latest kernel version that has been published.

local htmlparser = require("htmlparser")

local response = http.request{ url = "https://www.kernel.org/" }
local document = htmlparser.parse(response.body)

local found_elements = document:select("#latest_link a")
local latest_kernel_link = found_elements[1]
local latest_kernel_version = latest_kernel_link:getcontent()

return latest_kernel_version

Though, in this instance, it would be easier to just use their json list instead.

Down Service Watcher

This is a simple script that will alert you if any of the HTTP services go down.

local service_endpoints = {
  homepage = {
    name = "Bodge Homepage",
    url = "https://bodge.app/"
  },
  triggers = {
    name = "Bodge HTTP Triggers",
    url = "https://status.bodge.link/"
  }
}

--------------------------------------------------------------------------------

local results = {}

for id, service in pairs(service_endpoints) do
  local status, resp = pcall(http.request, { url = service.url })

  local isup = "true"
  local result
  if status and resp.statuscode == 200 then
    result = { up = true }
  else
    result = { up = false, status = type(resp) == table and resp.statuscode or tostring(resp) }
    isup = "false"
  end

  local skey = "isup_" .. id
  local wasup = storage[skey]

  if wasup ~= isup then
    if isup == "true" then
      alert.email{
        subject = "Service Recovered: " .. tostring(service.name),
        text = ""
      }
    else
      alert.email{
        subject = "Service Down: " .. tostring(service.name),
        text = "Status: " .. tostring(result.status)
      }
    end
  end

  results[id] = result
  storage[skey] = isup
end

return results