Deploying a REST API using Express to Elastic Beanstalk

A couple of weeks ago, I was trying to deploy a small service, but I didn’t wanted to start creating the full infrastructure suite on Fargate yet; hence, the best option is Elastic Beanstalk. For a couple of days I did the deployment manually, but after reading a little bit more about Beanstalk, I found a CLI that simplified a lot of the deployment process.

Here is some documentation if you want to read about it, but for the mean time, I will write a little bit about how I used it. It might be useful to you, if like me, you are looking for ways to do a quick deployment and don’t want to invest time in configuring the CI/CD pipeline or a more complex setup.

Prerequisites

The express application was built using:

  1. Node version 10.15.0

  2. generator-express-no-stress-typescript version 4.2.1

Installing the CLI

To install the CLI, there are two approaches, using HomeBrew or the other one using PIP. In my case, I used Brew because it’s so much simpler (and also because the other way failed for me :).

Just type the following and brew should take care of everything for you:

brew install awsebcli

Configuring the CLI

I’m going to assume you are already using AWS profiles in your machine, if not, I recommend reading about them here.

To start the configuration in your project, navigate to the root folder of it, and type the following command:

eb init —profile [YOUR PROFILE NAME]

It will start a series of questions in the next sequence:

  1. Region: in our case, we selected us-east-1

  2. Elastic Beanstalk Application: it will prompt you create a new app if none is already created.

  3. Platform: in our case, we selected node.js

  4. SSH configuration

  5. Keypair: to connect to the instance, you will need a key pair to use via SSH. The CLI will help you to create one as well.

Important: there is a step asking you if you want to use CodeCommit, this will help you create a pipeline, however, since we are using other source control tools, we ignored it.

Once the CLI finishes, you will see a new folder in your project called: .elasticbeanstalk (notice the dot at the beginning). If you wanna read more about configuration options, go here and here.

First deployment

Now that our app is configured (at least for starters), we need to do a deployment. For that, we need to create an environment with the command:

eb create [ENVIRONMENT NAME]

We used DEV, and after it finishes, we need to update some configuration in the AWS console. We will update the node command, this command is the one nginx will use whenever a new deployment is done.

Elastic Beanstalk environment configuration

Just one more thing, as you can see, the environment uses nginx as base server, so make sure that the application is listening on port 8081 (look at the documentation here). Finally, we can run:

eb deploy

Important: I had an issue, a really weird one when I started doing changes and deploying them, and it seemed like the deployment never grabbed the latest changes. After reading in internet for some time, I found this post; and in one of his IMPORTANT notes, Jared mentioned that the changes must be committed to Git for them to be deployed. I don’t have the answer to why this happens, but seems important to note.

If you are using plain javascript, this could be all, it will give you the URL to use to connect and whatever you have built, should be ready for usage. However, as many of my other posts, I like typescript, and this isn’t the end of our journey.

Deploying Typescript

Using typescript, the deployment is not as straightforward, so we need to add one more step to our config.yml file and in the package.json.

Important: these steps are necessary because Elastic Beanstalk do not install dev dependencies in their machines, so we need to overcome that issue with this new process.

First, we need to add something that helps us to do the compilation of Typescript to Javascript. For that, we will add a shell script in the root of our app with the following contents:

zip dist/$npm_package_name.zip -r dist package.json package-lock.json .env

Then, we will modify the package.json’s scripts with the following:

{
  ....
  "scripts": {
      "compile": "ts-node build.ts && tsc && sh dist.sh",
       ...
  },
  ...
}

And finally, in our config.yml file under the .elasticbeanstalk folder, we will add the following content before the global declarations:

deploy:
  artifact: dist/npm_package_name.zip

Now, let’s explain a little bit about what we are doing.

The scripts in the package.json file were updated to run the shell script after the compilation is finished.

The shell file grabs everything that was compiled and move it into a zip file.

Important: The “npm_package_name” in the shell file will refer to the package.json name attribute. Make sure that in the config.yml file, you type the same name

Next, in the config.yml, we specify the file that we will deploying to the environment in Elastic Beanstalk. So, the ebcli will only grab the zip file and send it. Under the hoods, elastic beanstalk will unzip it and run the command specified in the beanstalk environment.

Finally, run again the eb deploy command, and now our Typescript Express API will run in the cloud.

Summary

Now that all sections have been covered, I hope that the application has been a success and you have deployed your app into the cloud. If you have any comment, don't hesitate in contacting me or leaving a comment below. And remember to follow me on twitter to get updated on every new post.

Node.js and ORMs? TypeORM at your service

As I’ve mentioned in other posts, I’m working with more Node.js projects than ever and my experience with .NET applications is reducing (not complaining, if you think that). However, most of those projects have been with no-sql databases like DynamoDB and I haven’t had the need to use any ORM for it, even though there are options.

Recently, I was assigned a project that needed a big rescue. It’s an internal application of the company, rewritten many times but none of those times it has been completed, and the design itself wasn’t as good as you would like it to be. My assignment, design the architecture, define the technologies to be used, estimate it and assign tasks to a group of developers to work on it. So far, so good.

I decided to use React in the front end, and one main REST service in ExpressJS. Both solutions are going to be written in typescript. But what about the database? well, mysql was my choice and if you ask me the reason, it’s because the business logic makes more sense in a relational environment, but also because I want that my team (and myself) use an ORM to connect to a relational database like MySQL.

A quick search in Google will give you many results about ORMs but I found an interesting article that compares many of them and gives them a rank, take a look at it here. The only comment I would make there is that mongoose is limited to only one database, whereas TypeORM support multiple ones so in my mind, they should switch positions.

Ok, enough chit-chat, let’s start with the tech-y comments. First, I’m starting with a simple definition on an ORM.

What’s an ORM?

ORM stands for Object Relational Mapping, and it’s a mechanism that enables developers to manipulate data directly from the source without the hassle that it normally would take. They map the data sources to objects in code that can be queried, and the ORM transforms the actions over those objects to the specific commands in the specific data source. In other words, they abstract the data access layer from the developers and serves a “virtual object database” to be used within the programming language.

There are many ORM tools in the community, here are some of the most famous ones per programming language:

  1. Hibernate -> Java

  2. Entity Framework -> C#

  3. CakePHP -> PHP

  4. Django -> Python

  5. ActiveRecord -> Ruby

What’s TypeORM?

As the name suggests, and we have mentioned many times over the post, it is an ORM that runs in NodeJS; however it supports other environments like PhoneGap, React Native, Nativescript, etc.

It’s built to be used with Typescript or the latest versions of Javascript (from 5 to 8). Currently, version number is 0.2.9, but do not get fooled by this, it has over 3000 commits in Github! more than 40 thousand downloads per week! and finally, but not least, over 9000 stars!

The first version was deployed in December 6th of 2016, and had 36 releases since then. Being a young tool, it has been influenced by other ones like Hibernate and Entity Framework, so if you noticed stuff that feel familiar, it’s because they are.

From their website, here are some of the main features it provides:

  1. Both DataMapper and ActiveRecord

  2. Eager and Lazy relations

  3. Multiple inheritance patterns

  4. Transactions

  5. Cross-database queries

  6. Query caching

  7. Support for 8 different databases

  8. And many more here

Is there a model generator?

If you have worked with Entity Framework, you can do reverse engineering to create all the POCO classes from an existing database. Well, for TypeORM there is something similar.

Konnonable’s typeorm-model-generator package solves all of this for you. It can create all the object classes that you need to use in your application and it supports 6 databases, leaving Mongo and sql.js outside of the equation.

This package is even younger than typeorm, its first release was in July 2017 and it had 24 releases since then. It’s far less known in the community since there are not many downloads per week according to npmjs (around 300 per week).

Still, this package works like a charm and the configuration is as simple as you can imagine. Take a look at the next line:

typeorm-model-generator -e mysql -h [HOSTNAME] -d [DATABASE] -u [USER] -x [PASSWORD] -p 3306 --noConfig -o . --cf camel --ce pascal --cp camel --lazy

From it you can specify all the necessary parameters to establish a connection to a database, but also some configurations regarding the classes generated like the naming conventions and the “lazyness” of the relationships between them. If you want to take a look at all the available options for configuration, click here to view them.

Using TypeORM

After creating the classes with the typeorm-model-generator package, I ended up having classes that look something like this one:

import { Index, Entity, Column, OneToOne, OneToMany, ManyToOne, JoinColumn } from "typeorm";
import { UserStatus } from "./userStatus";
import { ProjectMember } from "./projectMember";
import { StatusReport } from "./statusReport";
import { TimeOff } from "./timeOff";

@Entity("User", { schema: "statusone" })
@Index("StatusTxt", ["statusTxt",])
export class User {
    @Column("varchar", {
        nullable: false,
        primary: true,
        length: 50,
        name: "UserNm"
    })
    userNm: string;

    @Column("varchar", {
        nullable: false,
        length: 150,
        name: "Email"
    })
    email: string;

    @Column("varchar", {
        nullable: false,
        length: 150,
        name: "FullNm"
    })
    fullNm: string;

    @ManyToOne(() => UserStatus, UserStatus => UserStatus.users, { nullable: false, onDelete: 'RESTRICT', onUpdate: 'RESTRICT' })
    @JoinColumn({ name: 'StatusTxt' })
    userStatus: Promise<UserStatus | null>;

    @OneToOne(() => ProjectMember, ProjectMember => ProjectMember.userNm, { onDelete: 'RESTRICT', onUpdate: 'RESTRICT' })
    projectMember: Promise<ProjectMember | null>;

    @OneToMany(() => StatusReport, StatusReport => StatusReport.userNm, { onDelete: 'RESTRICT', onUpdate: 'RESTRICT' })
    statusReports: Promise<StatusReport[]>;

    @OneToMany(() => TimeOff, TimeOff => TimeOff.userNm, { onDelete: 'RESTRICT', onUpdate: 'RESTRICT' })
    timeOffs: Promise<TimeOff[]>;
}

This one is an easy example of a User table in our database with its relationships like the status of the user, all the reports and more.

TypeORM uses heavily decorators, which requires some options to be enabled in the tsconfig file, however don’t worry about them since it’s explained in their installation instructions here. But if you want the easy route, here is mine.

{
  "compileOnSave": false,
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "esModuleInterop": true,
    "sourceMap": true,
    "moduleResolution": "node",
    "outDir": "dist",
    "typeRoots": ["node_modules/@types"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["typings.d.ts", "server/**/*.ts", "src/**/*.ts"],
  "exclude": ["node_modules"]
}

Ok, so our project have the classes from the database, and the typescript compiler recognizes all the decorators that TypeORM uses, so how do I use it??

I’m not going to expose the architecture I’m planning on using in the application, mostly because I haven’t completed it. But here is an example of a basic query I’ve done with TypeORM.

import {createConnection} from "typeorm";
import {User} from "../data-access/entity/User";

createConnection().then(async connection => {
      try {
        const users = await connection.manager.find(User);
        console.log("Loaded users: ", users); 
      } catch (error) {
        console.log(error);
      }
    }).catch(error => console.log(error));

Just as easy as it looks, you can obtain all the users from the database by creating a connection, and then using the connection manager to find all the objects from the class passed as parameter.

Another more complex query can be the following:

import {createConnection} from "typeorm";
import {User} from "../data-access/entity/User";

createConnection().then(async connection => {
      try {
        let projectMembers = await connection
            .getRepository(User)
            .createQueryBuilder("user")
            .innerJoinAndSelect("user.projectMember", "projectMember")
            .getMany();
        console.log("Loaded members: ", projectMembers); 
      } catch (error) {
        console.log(error);
      }
    }).catch(error => console.log(error));

In this example, we are creating a query that retrieves the relationship to ProjectMember for the users using a syntax called QueryBuilder which reminds me a lot of EntityFramework.

As far as query examples goes, I will stop here and suggest you to read more documentation like here or here.

Is there anything bad?

Nothing is perfect in this world, and I didn’t have to investigate a lot to find something that surprised me. Believe it or not, but apparently TypeORM still doesn’t support bit types for mysql (Check line 81 in this file).

Even though that this shocked me at first, I had the possibility of changing the design to overlook those bit types and use something different, however it’s still something that annoys me and they should add that support soon.

Summary

TypeORM is one more tool to our toolkit, one that will make your life a lot easier and have the support of a big community. It allows you to abstract a lot of the complex code that can come from connecting to a database, and helps you focus on your business instead of figuring out how to do a select in a table.

If you have any comment, don't hesitate in contacting me or leaving a comment below. And remember to follow me on twitter to get updated on every new post.