Your First Klotho App
tip
The examples ahead are written in JavaScript/TypeScript. We're currently working on support for Python, Go, Java, and C#.
This tutorial demonstrates how to create a plain Express.js REST API and use Klotho to transform it into a cloud-native one.
The tutorial will cover three core Klotho features that give your existing code cloud native capabilities. We call these Klotho capabilities.
Getting Started
Prerequisites
Before starting this tutorial, you must either install its prerequisites locally or you can get started more quickly by using our prepared Docker image.
- Locally Installed
- Docker
Required Software
- Klotho CLI installed
- Node.js 16.x+ (& NPM)
Required Software
Setting Up your Docker Environment
To set up your Docker environment, pull the latest Klotho image and set up aliases for the tools required by this tutorial by running the following commands in your terminal:
docker pull klothoplatform/klotho:latest
alias docker-klotho='docker run --platform linux/amd64 --rm -it -w /usr/src/project -v ~/.klotho:/root/.klotho -v "$PWD:/usr/src/project" klothoplatform/klotho:latest klotho'
alias docker-npm='docker run --platform linux/amd64 --rm -it -w /usr/src/project -v ~/.npm:/root/.npm -v "$PWD:/usr/src/project" klothoplatform/klotho:latest npm'
If you would like to make these aliases permanent, make sure to add them to the appropriate profile file for your preferred shell.
Application Overview
Your first Klotho application will be the doggie daycare sample application, (js-my-first-app
). The doggie daycare application is an Express app that listens on port 3000.
The server has two REST endpoints:
POST /pets
- Stores a new relationship between a pet and their owner in a key-value storeGET /pets
- Returns all pet/owner relationships from the key-value store
This application utilizes the following annotations:
Repository
Clone our sample apps git repo and install the npm packages for the js-my-first-app
app.
- Locally Installed
- Docker
git clone https://github.com/klothoplatform/sample-apps.git
cd sample-apps/js-my-first-app
npm install
git clone https://github.com/klothoplatform/sample-apps.git
cd sample-apps/js-my-first-app
docker-npm install
Compiling with Klotho
First, log in to Klotho. This will allow us to support you if you run into any issues, and give you the opportunity to shape the product in this early development stage.
- Locally Installed
- Docker
klotho --login # if you haven't already
docker-klotho --login # if you haven't already
Now compile the application for AWS by running klotho
and passing --provider aws
as an argument on the command line.
- Locally Installed
- Docker
klotho . --app my-first-app --provider aws
docker-klotho . --app my-first-app --provider aws
██╗ ██╗██╗ ██████╗ ████████╗██╗ ██╗ ██████╗
██║ ██╔╝██║ ██╔═══██╗╚══██╔══╝██║ ██║██╔═══██╗
█████╔╝ ██║ ██║ ██║ ██║ ███████║██║ ██║
██╔═██╗ ██║ ██║ ██║ ██║ ██╔══██║██║ ██║
██║ ██╗███████╗╚██████╔╝ ██║ ██║ ██║╚██████╔╝
╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
Adding resource input_file_dependencies:
Adding resource exec_unit:main
Found 2 route(s) on server 'app'
Adding resource gateway:pet-api
Adding resource persist_kv:petsByOwner
Adding resource topology:my-first-app
Adding resource infra_as_code:Pulumi (AWS)
Pulumi.my-first-app.yaml: Make sure to run `pulumi config set aws:region YOUR_REGION --cwd 'compiled/' -s 'my-first-app'` to configure the target AWS region.
The cloud version of the application is saved to the ./compiled
directory, and has everything you need to deploy, run and operate the application.
Examining the Compiled Output
As part of the compilation, Klotho generates a high-level topology diagram showing the cloud resources that will be used in your application's cloud deployment and their relationships.
Open ./compiled/my-first-app.png
to view the application's topology diagram:
We can see here that Klotho has defined the following AWS topology:
- main (Lambda) - The main Lambda function serves the Express app defined in
js-my-first-app
using a Lambda-compatible interface. - pet-api (API Gateway) - The pet-api API gateway is used to expose the Express routes defined in the main Lambda function.
- petsByOwner (DynamoDB Table) - The petsByOwner DynamoDB table is used by the main Lambda function to store the relationships between pets and their owners.
Concepts
Execution Unit
In the Klotho world, the main Lambda function is what's referred to as an execution unit. An application is composed of one or more execution units, with each execution unit being responsible for executing a discrete portion of the application's code. When using AWS, execution units are backed by compute resources such as Lambda functions or Docker containers running on Fargate (ECS or EKS).
Because @klotho::execution_unit
annotation is not used in this application, Klotho created a default execution unit for the application called main. When a default execution unit is created, Klotho determines its entrypoint by looking at the main
field in the project's package.json
file by default. However, the execution unit's entrypoint may be modified as a result of other Klotho annotations in the project (as we'll see in the next section).
Expose
Klotho was able to determine how to expose the application to the public using the @klotho::expose
annotation on the Application's Express app.listen
invocation.
/* @klotho::expose {
* id = "pet-api"
* target = "public"
* description = "Exposes the Pet API to the internet"
* }
*/
app.listen(3000, () => console.log('App listening locally on :3000'));
Annotating an Express app's app.listen
invocation with @klotho::expose
tells Klotho that you want to expose an Express application using an API Gateway, and also lets Klotho know that this Express app should be used as the entrypoint for all RESTful invocations of the execution unit serving it.
The target = "public"
directive tells Klotho that this app should be accessible publicly on the internet.
Persist (Key-Value)
The final core Klotho concept used by this project is the persist
capability denoted by the @klotho::persist
annotation.This annotation has a different meaning depending on where it is used. When used to annotate an ES6 Map
, Klotho will replace the Map
with a DynamoDB-backed implementation of a key-value store during the compilation process so you can use the same Map
semantics whether you are running the application locally or in the cloud.
For other ways to use @klotho::persist, check out our API reference.
As seen in the compiled output above, annotating the petsByOwner
ES6 Map
with @klotho::persist
resulted in Klotho generating petsByOwner
DynamoDB table.
/* @klotho::persist {
* id = "petsByOwner"
* }
*/
const petsByOwner = new Map();
Deploying the application
If you would like to deploy the application, refer to the deploying guide.
Testing Your Application
To test your endpoints, copy the api URL you see on your screen, from the end of the deploying step, and use these curl
commands:
note
These curls are examples and should be replaced with calls that are relevant to your service.
APP_URL=<app url from the pulumi output> # including the /stage
$ curl $APP_URL/pets -X POST -d '{"owner":"aaron", "pet":"fred"}' -H"Content-Type: application/json"
Added fred as aaron's pet
$ curl $APP_URL/pets
{"aaron":"fred"}
What next?
- Join Discord and chat with us. What went well, what went poorly, what are you looking forward to?
- Read through the nodejs API docs
- Read through our other tutorials:
- Creating a REST API
- Adding New Services and Routes
- Attaching a Domain to an API Gateway
- Event Driven Architecture
- Using Klotho with GitHub Actions
- Using Klotho with GraphQL Yoga and Express
- Key Value Stores
- Converting an AWS Lambda application to Fargate
- Multiple Deployment Enviroments With Klotho
- Using Klotho with NestJS and Sequelize
- Building a cloud-native Full-Stack NextJS + TypeORM application with Klotho
- Changing Pulumi Parameters
- Installing our Slack Notifier for Github
- TodoMVC and Klotho