Create Your First Lambda with Serverless, Typescript and Microgamma

davidecavaliere

Davide Cavaliere

Posted on January 16, 2020

Create Your First Lambda with Serverless, Typescript and Microgamma

@microgamma is a framework that I'm developing to make lamdba developing feel like a breeze. With it we can create microservices writing Typescript classes, bind class methods to specific lambda and use the serverless framework for deploying and monitoring without bothering writing much of the configuration needed into serverless.yml. @microgamma can also be used without serverless but I think that there is where it shines.

In this first post we'll use @microgamma/apigator and @microgamma/serverless-apigator serverless plugin. It is the first of a series of posts where we'll go through the creation of a microservice REST endpoint with DynamoDB and MongoDB including unit and integration tests.

In this first post we'll focus on

You can checkout the code hereby discussed by cloning this repo at the tag: my-first-apigator if you clone the repo you can skip the below section or just follow the readme in there.


Create a Typescript project

We'll use typescript-starter and I have to admit that it's not optimal for us right now as we'll need to clean some stuff up, though more other things are already done so we can leave with it for now.

npx typescript-starter my-first-apigator --node --yarn --no-vscode

Clean up

First we want to enable typescript decorators support.

--- a/tsconfig.json  
+++ b/tsconfig.json  
@@ -32,8 +32,8 @@  
     "pretty": true /* Stylize errors and messages using color and context. */,  

     /* Experimental Options */  
-    // "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,  
-    // "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,  
+     "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,  
+     "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,  

     "lib": ["es2017"],  
     "types": ["node"],  

Enter fullscreen mode Exit fullscreen mode

then we need to remove src/lib, src/types and delete the content of index.ts and clean tslint.json from Functional style rules.

--- a/tslint.json  
+++ b/tslint.json  
@@ -18,17 +18,9 @@  
     "no-let": true,  
     "no-object-mutation": true,  
     "no-delete": true,  
-    "no-method-signature": true,  
+    "no-method-signature": true  

-    // Functional style rules  
-    "no-this": true,  
-    "no-class": true,  
-    "no-mixed-interface": true,  
-    "no-expression-statement": [  
-      true,  
-      { "ignore-prefix": ["console.", "process.exit"] }  
-    ],  
-    "no-if-statement": true  
     /* end tslint-immutable rules */  
+  
   }  
 }  

Enter fullscreen mode Exit fullscreen mode

then also

--- a/tslint.json
+++ b/tslint.json  
@@ -10,15 +10,13 @@  
     // Recommended built-in rules  
     "no-var-keyword": true,  
     "no-parameter-reassignment": true,  
-    "typedef": [true, "call-signature"],  

     // Immutability rules  
     "readonly-keyword": true,  
     "readonly-array": true,  
     "no-let": true,  
     "no-object-mutation": true,  
-    "no-delete": true,  
-    "no-method-signature": true  
+    "no-delete": true  

     /* end tslint-immutable rules */  
Enter fullscreen mode Exit fullscreen mode

Lastly we want to remove the build:module from package.json and remove tsconfig.module.json

--- a/package.json  
+++ b/package.json  
@@ -12,7 +12,6 @@  
     "describe": "npm-scripts-info",  
     "build": "run-s clean && run-p build:*",  
     "build:main": "tsc -p tsconfig.json",  
-    "build:module": "tsc -p tsconfig.module.json",  
     "fix": "run-s fix:*",  
     "fix:prettier": "prettier \"src/**/*.ts\" --write",  
     "fix:tslint": "tslint --fix --project .",  
Enter fullscreen mode Exit fullscreen mode

and that's all for now.


Setup Serverless Framework and microgamma

yarn add -D serverless @microgamma/serverless-apigator

yarn add @microgamma/apigator @microgamma/digator

Create serverless.yml file with the following content

service: my-first-apigator # NOTE: update this with your service name  

provider:  
  name: aws  
  runtime: nodejs12.x  
  stage: dev  
  region: eu-west-2  


plugins:  
  - '@microgamma/serverless-apigator'  

custom:  
  apigator:  
    entrypoint: handler  
    buildFolder: build/main  


Enter fullscreen mode Exit fullscreen mode

Create your first service

Create src/my-first.service.ts file with the following content

// src/my-first.service.ts
import { Endpoint } from '@microgamma/apigator'; 
import { Injectable } from '@microgamma/digator';


// Define a new endpoint. This will be able to serve all the paths under the root `/` of your endpoint
@Endpoint({  
  // enable cors for this endpoint
  cors: true, 
  // just a reference name
  name: 'my-first-service',
  // this endpoint is public  
  private: false  
})  
@Injectable()
export class MyFirstService {}  
Enter fullscreen mode Exit fullscreen mode

With it we are defining a new endpoint without any lambda (method) yet.

We need to export a bootstrapped version of the service in src/handler.ts file such as:

// src/handler.ts
import { bootstrap } from '@microgamma/apigator';  
import { MyFirstService } from './my-first.service';  

export = bootstrap(MyFirstService);  
Enter fullscreen mode Exit fullscreen mode

This will be the code that will actually execute in aws. What the bootstrap does is basically to create a new instance of the given service.

Now let's check that it builds running yarn build.
A build folder shall be in your path with the following structure :

build/  
└── main  
    ├── handler.d.ts  
    ├── handler.js  
    ├── my-first.service.d.ts  
    └── my-first.service.js  
Enter fullscreen mode Exit fullscreen mode

Now let's create a first, very simple lambda:

// src/my-first.service.ts
import { Endpoint, Lambda } from '@microgamma/apigator';  
import { Injectable } from '@microgamma/digator';

@Endpoint({  
  cors: true,  
  name: 'my-first-service',  
  private: false  
})  
@Injectable()
export class MyFirstService {  

  @Lambda({  
    method: 'GET',  
    path: '/'  
  })  
  public index() {  
    return `Hello world! Today is ${new Date().toISOString()}`;  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

Deploy to aws

Build it again yarn build and deploy yarn sls deploy --stage dev

Output shall contain the following:

endpoints:  
  GET - https://xxxxxx.execute-api.eu-west-2.amazonaws.com/dev/  
Enter fullscreen mode Exit fullscreen mode

Which is the url of your lambda. Open your browser and hit that url or curl it ;)

You can also use serverless invoke command to invoke it from aws or locally.

Extra points

Deploy only what's strictly needed excluding everything but the build and node_modules folders.

--- a/serverless.yml  
+++ b/serverless.yml  
@@ -1,3 +1,5 @@  
 service: my-first-apigator # NOTE: update this with your service name  

 provider:  
@@ -14,3 +16,10 @@ custom:  
   apigator:  
     entrypoint: build/main/handler  
     buildFolder: /home/davide/dev/my-first-apigator/build/main  
+  
+package:  
+  exclude:  
+    - ./*  
+    - ./**  
+    - '!build/**'  
+    - '!node_modules/**  
Enter fullscreen mode Exit fullscreen mode

Add serverless monitoring. Check on serverless.com how to enable monitoring

--- a/serverless.yml  
+++ b/serverless.yml  
@@ -1,3 +1,5 @@  
+org: davidecavaliere  
+app: my-first-apigator  
 service: my-first-apigator # NOTE: update this with your service name  

 provider:  

Enter fullscreen mode Exit fullscreen mode

That's all folks. Hope you enjoyed and thanks for reading. Any feedback is very welcome and stay tuned for more @microgamma sugar.

💖 💪 🙅 🚩
davidecavaliere
Davide Cavaliere

Posted on January 16, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related