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-clicommand available.
Optional for REPL support
-
Babashka: makes the
bbcommand 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-bbIf 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-functionA new project is created for a function defined as my-bb-function. It will contain:
-
a
handlernamespace that is required for the template to work properly. This namespace needs to have a top-levelhandlerfunction with 0 or 1 arguments. -
a
bb.ednfile 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
testdirectory containing:-
run_tests.cljwith the namespace that will be used to run the tests. You can use any test library and test runner you like. -
a
bb.ednfile 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
- bazA 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 bazbecomes 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.ednfile 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: falseIf 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 bbSpins 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.cljtests.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-bbon 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.