Fennel in iocaine reference guide
Last updated: 2025-09-07

# Overview

One of the language options to write request handlers in is Fennel. Apart from configuration, writing the handler in Fennel is exactly the same as if you wrote it in Lua, but using Fennel’s syntax.

# Example

    (local patterns
        {:bad-bots (iocaine.Patterns "ClaudeBot" "GPTBot")})

    (fn is-bad-bot? [request]
      (when (patterns.bad-bots:matches (request:header "user-agent"))
        iocaine.outcome.Garbage))

    (fn knock-knock? [request]
      (when (not= (request:query "knock-knock") "a-human")
        iocaine.outcome.Challenge))

    (fn default [request]
      iocaine.outcome.NotForUs)

    (local rules [is-bad-bot?
                  knock-knock?
                  default])

    (fn decide [request]
      (accumulate [outcome nil
                   _ f (ipairs rules)
                   &until (not= outcome nil)]
        (f request)))

In this example, iocaine will first check whether the user agent matches a “bad-bot” pattern: if it does, the requested is accepted for serving Garbage. If not, it checks if the `knock-knock` query parameter is set to “a-human”, and if not, will make iocaine serve a Challenge. If both tests fall through, it defaults to considering the request “not for us” - rejecting it, and asking the reverse proxy to serve the request itself.

# See Also

There’s a short Getting Started guide, with a complete request handler example in Fennel. It’s a simple handler, but one that’s a reasonable starting point. For other, small examples, there are Fennel tests in the source code, too. Very basic, not particularly great as a starting point, but they showcase most features the engine.