AWS API + CLJS
Tags: aws, clojure, clojurescript, javascript
Published: 2018-12-17 16:44:37

---
title: AWS API + CLJS
published: true
description: Introduction into leveraging the power of AWS from Clojurescript
tags: AWS, Clojure, Clojurescript, Javascript
cover_image: https://thepracticaldev.s3.amazonaws.com/i/bbohkwgz7bdcd960mqle.png
---
#Building on our own shoulders
[Previously](https://dev.to/royalaid/cljs-s-lambda-697) we built a simple AWS Lambda. Today we are going mess around with the AWS Node SDK and DynamoDB. The main goal of this post is to show more serious inter-op between Clojurescript and Javascript. 

#AWS Services
![Image of AWS Services Dashboard](https://thepracticaldev.s3.amazonaws.com/i/vfypyrxsekhw72m659co.png)
AWS offers a lot of services for lot of different business needs and getting started can be really overwhelming. Before starting this blog anytime I needed to use AWS at work I was nervous. Coworkers through around nonsense acronyms left and right. "Check the Codebuild step in the Codepipeline to see if there is a problem with S3 or IAM" makes no sense if you haven't used AWS before. Luckily climbing over that hurdle really doesn't take more than a few hours of googling and poking around and hopefully this post will help anyone trying to get involved in the AWS ecosystem. Just to steer our exploration we will be using DynamoDB but if something else seems cool I highly encourage you to check out the intro project and docs!

#🍖The actual meat🍖
For this posts example code I have ported the Node SDK's [Create Table](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.01.html), [CRUD Operations](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.03.html), and [Delete Table](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.05.html).

##Link to repo
{% github royalaid/Shadow-Node-AWS %}

##Tools
We will obviously need a few tools:
 * [AWS CLI] (https://aws.amazon.com/cli/) We need the CLI because it gives us auth into AWS, more info on setting up the CLI [here](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html)
 * [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)/[Yarn](https://yarnpkg.com/en/) (for package management and to use the Shadow-CLJS CLI)
 * [Shadow-CLJS](https://shadow-cljs.github.io/docs/UsersGuide.html#_standalone_via_code_npm_code) (Our CLJS Build tool of choice mainly because it makes [consuming npm deps super easy](https://shadow-cljs.github.io/docs/UsersGuide.html#_using_npm_packages))

##CLJS VS JS
######Note: I have basically ported the JS to it's literal, but not idiomatic, CLJS equivalent. I would use this code to help get a better understanding of how the two languages relate and how to call one from the other. I would *NOT* code like this when using CLJS as the primary language.

In this post I will just break down on example, `createTable`, because the only difference between any of the examples is the `params` var and the `dynamodb`/`docClient` fn call. 

###JS for reference

```javascript
var AWS = require("aws-sdk");

AWS.config.update({
  region: "us-west-2",
  endpoint: "http://localhost:8000"
});

var dynamodb = new AWS.DynamoDB();

var params = {
    TableName : "Movies",
    KeySchema: [       
        { AttributeName: "year", KeyType: "HASH"},  //Partition key
        { AttributeName: "title", KeyType: "RANGE" }  //Sort key
    ],
    AttributeDefinitions: [       
        { AttributeName: "year", AttributeType: "N" },
        { AttributeName: "title", AttributeType: "S" }
    ],
    ProvisionedThroughput: {       
        ReadCapacityUnits: 10, 
        WriteCapacityUnits: 10
    }
};

dynamodb.createTable(params, function(err, data) {
    if (err) {
        console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
    }
});
```

###CLJS
```clojure
(ns server.create-table
  (:require ["aws-sdk" :as AWS])) ;; Our var AWS = require statement

(AWS/config.update #js{:region "us-east-1"})
;; first example of js interop, the translates to the AWS.config.update above, the AWS/ bit is used for accessing the CLJS "Namespace" for the AWS SDK

(def dynamo (AWS/DynamoDB.  #js{:apiVersion "2012-08-10"}))
;; Second example of interop and shows constructor invocation. It can also be written as (def dynamo (new AWS/DynamoDB  #js{:apiVersion "2012-08-10"})) because the . is shorthand for new
;;Additionally def is the CLJS equivalentish of var but isn't used as often as in Clojure/script

(def params
  (clj->js {:TableName "Movies",
            :KeySchema
            [{:AttributeName "year", :KeyType "HASH"}
             {:AttributeName "title", :KeyType "RANGE"}],
            :AttributeDefinitions
            [{:AttributeName "year", :AttributeType "N"}
             {:AttributeName "title",
              :AttributeType "S"}],
            :ProvisionedThroughput
            {:ReadCapacityUnits 10,
             :WriteCapacityUnits 10}}))

(defn invoke []
 (.createTable dynamo params
               #(if %1
                  (js/console.error "Unable to create table. Error JSON:"
                                    (js/JSON.stringify %1 nil 2))
                  (js/console.log "Created table. Table description JSON:"
                                  (js/JSON.stringify %2 nil 2)))))
;; This is the one difference from the AWS example code above, the actual call to AWS is wrapped in a function so it can be call from node.js proper.
```

This pattern follows through all the the rest of the examples.

##Node.js REPL calls
If you want to be able to test the code out for yourself you can call into from a node.js repl just compile and require
```
npx shadow-cljs compile app
cd target
node
```
then once in the repl
```
var m = require('./main.js');
m.aws.createTable() //Other options include getItem, createItem, readItem, deleteTable, deleteItem, updateItem, updateItemConditionally, atomicInc
//Inside of the Shadow-CLJS config is a mapping between the CLJS fn's to the m.aws object
```
#🎉🎉🎉
And there we have it! If you have any questions or feedback reach out on [Twitter](https://twitter.com/s0xks), or @royalaid on the Clojurians [Slack](https://clojurians.slack.com/) or [Zulip](http://clojurians.zulipchat.com/)