Hello Serverless with Jets and Dynamoid
Tags: serverless, aws, jets, ruby
Published: 2019-01-15 11:09:10

---
title: Hello Serverless with Jets and Dynamoid
published: true
description: Learn how to use Jets framework and Dynamoid to build a simple serverless app
tags: serverless, aws, jets, ruby
cover_image: https://thepracticaldev.s3.amazonaws.com/i/9ro6az33cayzu4x6l4he.png
---

[Jets](http://rubyonjets.com) is a Ruby framework which allows us to easily create and deploy serverless applications to AWS. Jets is adopting several concepts and patterns from Rails, which makes much easier the adoption of serverless architectures by Rails developers.

Jets is in early stages of maturity, however, its creator, [Tung Nguyen](https://github.com/tongueroo), is making a lot of effort to improve the framework and the community around it is growing.

The application we'll be using as an example is the same previously used in [Building AWS Lambdas for Real World using Ruby and Serverless Framework](https://dev.to/jalerson/building-aws-lambdas-for-real-world-using-ruby-and-serverless-framework-2p49): a simple app which will consume data posted by Github. This sample project is available [clicking here](https://github.com/jalerson/jetsapp).

Like [Leeroy Jenkins](https://www.youtube.com/watch?v=mLyOj_QD4a4) would say: *Alright, time's up! Let's do this!*

# Prerequisites

Obviously, have Jets installed is necessary. If you don't have, go to your terminal and install it:

```
$ gem install jets
```

In order to deploy your app to AWS, you'll need to have your AWS keys set up in `~/.aws/credentials`. In case you don't have, please refer to [Configuration and Credential files](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).

# Creating our Jets app

Since we're not interested in assets serving, let's create our app using API mode:

```
$ jets new jetsapp --mode=api
$ cd jetsapp
```

By default, Jets supports [ActiveRecord](http://rubyonjets.com/docs/database-activerecord/) and DynamoDB via [Dynomite](https://github.com/tongueroo/dynomite). However, I'm interested in something different here: I want to use [Dynamoid](https://github.com/Dynamoid/dynamoid), which is a stable and mature Ruby ORM for AWS DynamoDB.

That said, let's update our Gemfile to add Dynamoid and remove mysql2.

```
# gem "mysql2", "~> 0.5.2"
gem 'dynamoid', '~> 3.1.0'
```

Don't forget to update your dependencies by executing `bundle install` in your terminal.

Dynamoid requires AWS credentials in order to properly connect to DynamoDB. If we were in Rails, we could easily do it using [initializers](https://guides.rubyonrails.org/configuring.html#initialization-events). Fortunately, [initializers are one of the cool stuff adopted by Jets](http://rubyonjets.com/docs/initializers/) from Rails.

So, we just need to create `config/initializers/dynamoid.rb` and add the following:

{% gist https://gist.github.com/jalerson/b08a1143f2776fb55efb6a1509c0f8f9 %}

We're configuring the `namespace`, which is optional (default is `dynamoid`) and it's a prefix for our DynamoDB tables. We're also setting our AWS access key id, secret key and region. Obviously, we're keeping all these data in our environment variables.

Last but not least, we're creating DynamoDB tables based on the models we have in `app/models`. Don't worry about the recreation of these tables when you perform a redeploy: Dynamoid takes care of it.

Now, let's update our `.env` file:

```
ACCESS_KEY_ID=<your_access_key_id>
SECRET_ACCESS_KEY=<your_secret_access_key>
REGION=<region>
```

**Important**: while writing this article, I figured out that are some [environment variable names reserved by AWS](https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html#lambda-environment-variables), for instance, `AWS_REGION`. So take care to not use them :D

### Models

Let's continue updating the `app/models/application_item.rb`, which is intended to be the parent class of all DynamoDB models. The default `ApplicationItem` generated by Jets looks like this:

{% gist https://gist.github.com/jalerson/3f16ea32455bcc02041dce5b2edb4925 %}

Since we're not using `Dynomite`, we can remove it and include the `Dynamoid::Document`.

{% gist https://gist.github.com/jalerson/69080e75bd35ef2f42d0331bc520d5d4 %}

After that, let's build our `GithubEvent` model.

{% gist https://gist.github.com/jalerson/23835e14895cd1a1fdc308b33e0d0f58 %}

As you can see, we're defining the table name, fields names and types (the default is `string`), as well as some validation rules. [Dynamoid automatically creates three fields](https://github.com/Dynamoid/dynamoid#magic-columns): `id` (string), `created_at` (datetime) and `updated_at` (datetime).

Dynamoid also allows use to use: [default field values](https://github.com/Dynamoid/dynamoid#default-values), [custom field types](https://github.com/Dynamoid/dynamoid#custom-types), [associations](https://github.com/Dynamoid/dynamoid#associations), [validations](https://github.com/Dynamoid/dynamoid#validations), [callbacks](https://github.com/Dynamoid/dynamoid#callbacks), [STI (Single Table Inheritance)](https://github.com/Dynamoid/dynamoid#sti), [record creation](https://github.com/Dynamoid/dynamoid#object-creation), [querying](https://github.com/Dynamoid/dynamoid#querying) and much more.

### Controller

Using Jets, we can create a simple [lambda function](http://rubyonjets.com/docs/functions/), or we can build our controller and each action will be transformed into an AWS lambda function. Let's use the second approach just because we can!

{% gist https://gist.github.com/jalerson/e6a730968f4667b4d42fe2ab257be406 %}

The `github` action will be responsible for receiving Github events data. The implementation couldn't be simpler! As you can see, even though we're not implementing a lambda function (which has the `event` and `context` arguments), the `event` variable is available. Btw, `params` is also available!

### Finishing

Let's add the route to our `config/routes.rb` file:

{% gist https://gist.github.com/jalerson/4a2673fb650f9154f34cfaad7a265618 %}

And finally, execute `jets deploy` in our terminal to deploy our application. If you don't want to use the default profile to deploy, simply execute `AWS_PROFILE=<profile_name> jets deploy`.

## Final considerations

I really like the idea of Jets framework: to bring concepts and patterns from Rails world to make our lives easier while migrating to serverless. Although the framework is still not mature for critical applications, I will definitely give it a try.

Special thanks to [Tung Nguyen](https://twitter.com/tongueroo) for the awesome support!

# Looking for a job?

If you're looking for a job and are willing to relocate to Frankfurt (Germany), consider to take a look on the [positions available at creditshelf](https://creditshelf-jobs.personio.de/?language=en#department-43306).