CLJS ❤️'s Lambda
Tags: clojure, clojurescript, lambda, serverless
Published: 2018-12-08 21:46:57

---
title: CLJS ❤️'s Lambda
published: true
description: Plug together CLJS, Shadow-CLJS, and AWS Lambda
tags: clojure, clojurescript, lambda, serverless
---

# What is Clojure and why do you care?

Because every post about Clojure or Clojurescript (CLJS) has to explain what Clojure(script) is and why you should use it:
{% twitter 1068978794910777344 %}

But in all seriousness a bunch of people have done better introductions to Clojure then this post will:

* [Clojure for the Brave and True](https://www.braveclojure.com/introduction/)
  * How I learned Clojure (Long)
* [Learn Clojure in Y Minutes](https://learnxinyminutes.com/docs/clojure/)
  * A great overview of the language in a file you can run at the [REPL](https://clojure.org/guides/repl/introduction) to test (Short)
* [Hypi's Intro to Clojure Post](https://hypi.io/blog/solutions/introduction-to-clojure/)
  * A good middle ground between the above

# 🔥Serverless🔥

Unfortunately there isn't an amazing parody commercial for Serverless so instead let's just try to actually motivate why you should care about it. Serverless is just a shorthand for describing a way to run code without worrying about infrastructure. What does that mean practically? Give them and zip and they throw it on some unused hardware, that's it! 

It supported on [AWS](https://aws.amazon.com/lambda/), [Google Cloud](https://cloud.google.com/functions/), and [Azure](https://azure.microsoft.com/en-us/services/functions/) and probably other clouds. Because the examples are built with AWS that is where we will focus. 

Probably the [biggest](https://alestic.com/2016/12/aws-invoice-example/) motivator for migrating to or build new services with serverless is [cost](https://www.troyhunt.com/brief-lessons-on-handling-huge-traffic-spikes/). The the [free tier](https://aws.amazon.com/lambda/pricing/) is very generous and it's pay as you go so it's free to prototype!

![Eyes popping](https://media.giphy.com/media/12eOoLezVypVWo/giphy.gif)

You also get ease of deployment/operation and native integration with your cloud provider making it super easy to tap into services like cloud provided DBs, metrics/analytics, queues, email services, etc.

# CLJS + Lambda
While there exist ways for you to plug together [Clojurescript and Lambda](https://github.com/nervous-systems/cljs-lambda) they are coupled to specific build tooling and are a bit too much like a black box for my liking. This also is a good excuse to learn how all the pieces plug together. This post is a distillation of how to do just that. Before finally getting to the meat of the post we have to introduce one more player to the stage.

## Shadow-CLJS
[Shadow-CLJS](http://shadow-cljs.org/) is an alternative frontend to the Clojurescript compiler, it is fills the same role as [lein-cljsbuild](https://github.com/emezeske/lein-cljsbuild) or [Figwheel-main](https://github.com/bhauman/figwheel-main) if you are familiar with the space. The big advantage it has over the others tools is [awesome npm support](https://code.thheller.com/blog/shadow-cljs/2017/11/10/js-dependencies-in-practice.html). We can use basically  all of npm with CLJS via Shadow which is important if we want to leverage things like [AppSync](https://aws.amazon.com/appsync/) or the [AWS Node SDK](https://aws.amazon.com/sdk-for-node-js/).

# MAKE THE DAMN LAMBDA ALREADY
## Setup
Okay to being lets make a lambda, eventually we will throw away everything inside of it, but for now just leave it be.
![](https://thumbs.gfycat.com/CraftyGroundedGrassspider-size_restricted.gif)
And with our basic lambda up we just need our tools and some example code, first the tools:
`brew install yarn #Or your OS equiv, apt-get, yum, etc`
And that's it!

##Example Code
For the example code I have forked [Chenyong's](https://github.com/chenyong) minimal [Shadow + Node example](https://github.com/minimal-xyz/minimal-shadow-cljs-nodejs) to create a hello world lambda with Shadow:
{% github royalaid/minimal-shadow-cljs-nodejs %}
```
git clone https://github.com/royalaid/minimal-shadow-cljs-nodejs.git /tmp/lambda-example
cd /tmp/lambda-example
yarn
```
and now all of your deps are setup!

##Code Breakdown
While the project should be pretty self explanatory I will given a high level overview of the important bits, the `shadow-cljs.edn` and `src/server/main.cljs` files.

###shadow-cljs.edn
The `shadow-cljs.edn` is the equivalent of `project.clj` for lein or `boot.clj` for boot, its the build configuration file for Shadow. The most important part of that file for us is the `:target :node-library` line which tells shadow to setup `module.exports` for use by node, this is bridge between the CLJS code with write and the Javascript that Node reads. The second most important line is `:exports {:handler server.main/handler}`. This line tell Shadow what to call the export and then what CLJS function to bind to it, in our case the handler function in the Clojurescript namespace `server.main`. This function is what AWS will end up calling when we execute the lambda.

###main.cljs
As for the `src/server/main.cljs`, this is what will eventually be run by AWS after Shadow transpiles it for us. The lone function inside of the namespace is what actually invoked. Important note, the function signature has to have 3 args (2 if using async/await, which we aren't) and must "return" its value by then invoking the `cb` arg and passing the result to the second arg of that callback (`cb`) invocation.

We need to do this because Lambda expects the result to come as a promise or from the callback passed in. This took me waaaaaaaaay too long too piece together and hopefully this won't trip up anyone else either. Additionally we need to be sure to return Javascript values and not Clojurescript values hence the use of `#js` for the array.

##Build and release time
######Note: I am going to skip the process of actually developing the code but check out the earlier linked [Shadow + Node example](https://github.com/minimal-xyz/minimal-shadow-cljs-nodejs) for details and workflow for how to use Shadow with Nodejs and hot-reloading.

```
cd /tmp/lambda-example # Get you back to the correct directory
yarn shadow-cljs release app # This transpiles and optimizes your CLJS
zip -r archive.zip target # Prep your output for upload to Lambda
```
Then we just upload our new zip to our old Lambda and point the handler function  at our CLJS function (which will be <name of js file>.handler, main.handler in the recording).

![](https://thumbs.gfycat.com/IllTinyApisdorsatalaboriosa-size_restricted.gif)

#🎉🎉🎉
And there we have it! If you have any questions or feedback reach out on [Twitter](https://twitter.com/s0xks), [Mastodon](https://royalaid.me/@admin), or @royalaid on the Clojurians [Slack](https://clojurians.slack.com/) or [Zulip](http://clojurians.zulipchat.com/)