The ergonomics of Babashka, combined with the simplicity of Clojure, make it a great choice for writing Functions in OpenFaaS, from single purpose Functions, to frontend facing REST APIs, to serving hiccup backed HTML pages - delivered with a back-to-back joyful development experience.
Babashka is designed for minimal memory usage, allowing you to scale up your narrow-purposed Functions with comparable RAM consumption.
Babashka scripts run immediately, ensuring:
-
that Function cold start times are kept to a minimum.
-
a rapid development feedback loop.
-
a simple REPL workflow - just start everything all over again, it’s fast.
-
OpenFaaS CLI: makes the
faas-cli
command available.
Optional for REPL support
-
Babashka: makes the
bb
command available. -
rlwrap: readline support, here for Babashka REPL.
To create Babashka Functions with this template, use the following command once:
faas-cli template pull https://github.com/ccfontes/faas-bb
If you ever need to update the template, simply run the command above with the --overwrite
flag.
Create Babashka Functions as with the following command example:
faas-cli new --lang bb my-bb-function
A new project is created for a function defined as my-bb-function
. It will contain:
-
a
handler
namespace that is required for the template to work properly. This namespace needs to have a top-levelhandler
function with 0 or 1 arguments. -
a
bb.edn
file where ship dependencies can be added. Remove this file if you don’t need to add any dependencies or run a REPL without passing the classpath explicitly. -
a
test
directory containing:-
run_tests.clj
with the namespace that will be used to run the tests. You can use any test library and test runner you like. -
a
bb.edn
file where test dependencies can be added. Remove this file if you don’t need to add any dependencies.
-
In bb
language:
(defn handler [{:keys [headers body context] :as event}]
...)
event
is a map containing :headers
, :body
and :context
keys.
:headers
contains headers, as such:
{:content-type "application/json"}
:body
is the payload body. When passing a JSON object payload and using bb
language, the payload will be automatically parsed as a Clojure map with keyword keys. There are cases where it’s preferable to have string keys in the payload body, and it’s possible to support them by setting keywords: false
in the Function in stack.yml
:
my-function:
lang: bb
handler: ./anything/my-function
image: ${DOCKER_REGISTRY_IMG_ORG_PATH}/my-function
environment:
keywords: false
:context
contains environment variables. Additional environment variables can be defined in the stack.yml
file, as such:
my-function:
lang: bb
handler: ./anything/my-function
image: ${DOCKER_REGISTRY_IMG_ORG_PATH}/my-function
environment:
MY_ENV1: foo
MY_ENV2: 2
:context
will contain:
{:my-env1 "foo"
:my-env2 2}
If you declare secrets in the stack.yml
file, these will be available in :context
map as well. Let’s start with an example:
my-function:
lang: bb
handler: ./anything/my-function
image: ${DOCKER_REGISTRY_IMG_ORG_PATH}/my-function
secrets:
- foo
- baz
A secret value that is an EDN string, when internally parsed as a Clojure map, will have its content spliced into the :context
map. Otherwise, the secret will be available in the :context
map as {:secret-name <secret-value>}
, with <secret-value>
parsed as a Clojure data structure other than a map.
Following up from the definition of my-function
above, we define the following secrets:
echo 'bar' | faas-cli secret create foo
echo '{:spam "eggs"}' | faas-cli secret create baz
becomes this in the :context
map:
{:foo "bar" :spam "eggs"}
Tests for your Function run when you build the Function image (faas-cli build
).
A test
directory in the Function’s top-level directory is provided, containing:
-
run_tests.clj
, with the namespace that will be used to run the tests. You can use any test library and test runner you like. -
a
bb.edn
file where test dependencies can be added. Remove this file if you don’t need to add any dependencies.
To disable running existing tests, set the TEST
build time argument to false
:
my-function:
lang: bb
handler: ./anything/my-function
image: ${DOCKER_REGISTRY_IMG_ORG_PATH}/my-function
build_args:
TEST: false
If you don’t plan on testing, you can remove the test
directory altogether.
Existing test files are removed from the final Docker image used to run the Function in OpenFaaS.
Spin up a REPL in the context of your Function project.
Note
|
You’ll need to have Babashka installed in your local. |
In the root directory of your Function run:
rlwrap bb
Spins up a REPL with readline support.
If you remove bb.edn
with just {:paths ["."]}
in it, the Function will still work, but then you will need to explicitly pass the classpath when spinning up a REPL:
rlwrap bb -cp .
See the examples directory to find a fully working set of OpenFaaS Functions written in Babashka.
All tests run in CI with Github Actions. Some commands can be found in a Github Actions workflow to help you with testing your changes before pushing them to a topic branch.
Run locally the unit tests for the bb
template.
The requirement is that babashka (bb
) is installed.
cd template/bb
bb --config tests.edn tests.clj
tests.clj
is included with the template so you can test any changes you make to the template before using it.
-
MailBriefly.com is using
faas-bb
on all its microservices (with joy).
Contributions are welcome! If you find a bug or have an idea for a new feature, please open an issue or submit a pull request.
The template may benefit from some common middleware functions, such as those offered in the ring-defaults library. Users are welcome to recommend integrating any middleware they think would be useful for handling common web application needs.
The following files are derived from ring to work with Babashka, originally authored by James Reeves and contributors, and used under the MIT license: ring.middleware.json, ring.util.io, ring.util.mime-type, ring.util.parsing, ring.util.response, ring.util.time.