Dart on AWS Lambda
Tags: computerscience, programming, dart, aws
Published: 2021-11-03 15:33:22

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:paragraph -->
<p>We will cover briefly:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Dart runtime for AWS Lambda</li><li>Write lambda (using Dart)</li><li>Adding a POST endpoint</li><li>Deploy lambda on AWS</li></ol>
<!-- /wp:list -->

{% youtube YPBaruL2JRc %}

<!-- wp:heading {"level":3} -->
<h3>Dart runtime for AWS&nbsp;Lambda</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>With the introduction of <a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html" rel="noreferrer noopener" target="_blank">custom AWS Lambda runtimes</a>, it is possible to implement a runtime in any programming language.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>AWS Lambda provides an HTTP API for <a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html" rel="noreferrer noopener" target="_blank">custom runtimes</a> to receive invocation events and send response data back within the Lambda <a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html" rel="noreferrer noopener" target="_blank">execution environment</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Using the custom AWS Lambda runtime, we can also run Dart on Lambda with the <a href="https://aws.amazon.com/blogs/opensource/introducing-a-dart-runtime-for-aws-lambda/" rel="noreferrer noopener" target="_blank">recently published runtime</a> for the Dart programming language.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>AWS released a pub package <code><a href="https://pub.dev/packages/aws_lambda_dart_runtime" rel="noreferrer noopener" target="_blank">aws_lambda_dart_runtime</a></code> that packages the dart runtime to build lambda functions with AWS events.</li><li>It shows two ways to deploy the dart based lambda functions</li></ul>
<!-- /wp:list -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*XBfz1sa6B7fJoRikUAtOoA.png" alt="Dart based lambda"/><figcaption>Dart based&nbsp;lambda</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>In this article, we will go with the <strong>Serverless Framework</strong> approach</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Write lambda (using&nbsp;Dart)</h3>
<!-- /wp:heading -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Pre-Requisite: You should have the aws cli configured in your machine. Check <a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html" rel="noreferrer noopener" target="_blank">here</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>We will make use of the <a href="https://www.serverless.com/" rel="noreferrer noopener" target="_blank">serverless</a> framework to write lambda functions.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>As per the docs,</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Develop, deploy, troubleshoot and secure your serverless applications with radically less overhead and cost by using the Serverless Framework. The Serverless Framework consists of an open source CLI.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Serverless allows us to focus on the code, while it takes care of the setting up policies, and provisioning of required infrastructure onto AWS.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To install <code>serverless</code>, follow <a href="https://www.serverless.com/framework/docs/getting-started" rel="noreferrer noopener" target="_blank">here</a>. Personally, I configured using the below</p>
<!-- /wp:paragraph -->

```yml
npm install -g serverless
```

<!-- wp:heading {"level":4} -->
<h4>Setup for&nbsp;Dart</h4>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>Currently, <code>serverless</code> has no support for dart, but there is a serverless plugin for Dart applications, called <a href="https://github.com/katallaxie/serverless-dart" rel="noreferrer noopener" target="_blank"><strong>serverless-dart</strong></a><strong> </strong>We will install <code>serverless-dart</code> using</li></ul>
<!-- /wp:list -->

```yml
npm i -D serverless-dart
```

<!-- wp:list -->
<ul><li>Now, this plugin builds the dart lambda using docker, hence we also need to <a href="https://docs.docker.com/get-docker/" rel="noreferrer noopener" target="_blank">install docker</a></li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: In case something goes wrong, try installing the <code>serverless</code> framework, see above.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":4} -->
<h4>Create a Dart&nbsp;Project</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Once the above setup is configured, it’s time to create a dart project. We make use of the below</p>
<!-- /wp:paragraph -->

```yml
npx serverless install \
  --url https://github.com/katallaxie/serverless-aws-dart \
  --name hello
```

<!-- wp:paragraph -->
<p>This will download the source of a sample Dart application and unpack it as a service named <code>hello</code> in a directory called <code>hello</code></p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*ZAFWU4vsu3P-LzPkl-t62w.png" alt="Structure of the application"/><figcaption>Structure of the application</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>I didn’t need the&nbsp;<code>.github/workflows</code> hence, deleted the folder.</li><li>If we look into <code>pubspec.yaml</code> we will see the package <code>aws_lambda_dart_runtime</code> and <code>build_runner</code> under dev dependencies. We give both a version number.</li></ul>
<!-- /wp:list -->

```yml
dependencies:
  aws_lambda_dart_runtime: ^1.1.0
dev_dependencies:
  build_runner: ^2.1.0
```

<!-- wp:paragraph -->
<p>Next, we look into the <code>serverless.yml</code> which is the brain behind this application. We modify the yml file with this</p>
<!-- /wp:paragraph -->

```yml
service: hello
provider:
  name: aws
  runtime: dart
  lambdaHashingVersion: 20201221
  memorySize: 128
package:
  individually: true
plugins:
  - serverless-dart
functions:
  hello:
    handler: main.hello
    events:
      - http:
          path: /hello
          method: GET
```

<!-- wp:paragraph -->
<p><strong>service</strong>: Name of the service (<code>hello</code> in our case)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>functions</strong>: The functions to be exposed, along with their entry points. We currently have a function called <code>hello</code> Inside that, we specify the different configurations.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>handler</strong>: This is the AWS registered handler and should be the same as inside our <code>main.dart</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>events</strong>: The events that trigger this function. This includes <code>http</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>http</strong>: REST API endpoint (API Gateway v1)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>path</strong>: Path for this endpoint<code>/hello</code> and method being <code>GET</code></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: For detailed description: see <a href="https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml" rel="noreferrer noopener" target="_blank">here</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":4} -->
<h4>Inspecting the main&nbsp;dart</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We are left with one important file to inspect <code>main.dart</code> . We will change the contents of the file to below</p>
<!-- /wp:paragraph -->


```dart
// IMPORT OMITTED FOR BREVITY
void main() async {
 Handler&lt;AwsApiGatewayEvent> helloApiGateway=(context,event) async {
  final resp = {
    'message': 'Hello to ${context.requestId}',
    'host': '${event.headers.host}',
    'userAgent': '${event.headers.userAgent}',
  };
  final response = AwsApiGatewayResponse(
    body: json.encode(resp),
    isBase64Encoded: false,
    statusCode: HttpStatus.ok,
    headers: {
      "Content-Type": "application/json",
    },
  );
  return response;
};

Runtime()
..registerHandler&lt;AwsApiGatewayEvent>("main.hello", helloApiGateway)
..invoke();
}
```

<!-- wp:list -->
<ul><li>Every dart program begins with the call to <code>main</code>function.</li><li>The methods such as Handler, Runtime, etc are present inside the <code>aws_lambda_dart_runtime</code> package.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4>HelloApiGateway</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We define a <code>helloApiGateway</code> which is the handler to be invoked once our API gets hit. This is of the type <code>AwsApiGatewayEvent</code> and exposes two important fields: <code>Context</code> and <code>AwsApiGatewayEvent</code>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>The <code>Context</code> contains the Lambda execution context information. It comprises various parameters such as <code>requestId</code> etc.</li><li><code>AwsApiGatewayEvent</code> is one of the events supported by the package. An <code>Event</code> is basically an abstraction for every event that can be ingested by a handler. It comprises of implementations such as <code>AwsCognitoEvent</code>&nbsp;, <code>AwsS3Event</code>&nbsp;, <code>AwsKinesisDataStreamEvent</code> etc</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>In our case, we register the event of type <code>AwsApiGatewayEvent</code> Hence, we can extract the details out of the incoming request. These details include <code>headers</code>&nbsp;, <code>body</code>&nbsp;, <code>queryStringParameters</code> etc</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Finally, for sending the response back to the client, we make use of <code>AwsApiGatewayResponse</code>&nbsp;</li><li>We specify the <code>body</code> to the sent, along with the additional parameters such as <code>isBase64Encoded</code>&nbsp;, <code>statusCode</code> and <code>headers</code></li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4>Register HelloApiGateway</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Once the handler is written, now we need to register it to our <code>Runtime</code></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>This is done using <code>registerHandler</code> which takes in two required parameters: a string name and our gateway</li><li>Under the name, we specify <code>main.hello</code> (which is the same as specified inside the <code>serverless.yml</code>)</li><li>Finally, we call <code>invoke</code> to run the <code>Runtime</code> in loop and digest events that are fetched from the API.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>Adding a POST&nbsp;Endpoint</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Inside our <code>serverless.yml</code> add another endpoint for the post-service</p>
<!-- /wp:paragraph -->

```yml
functions:
  hello:
    handler: main.hello
    events:
      - http:
          path: /hello
          method: GET
  postRequest:
    handler: main.postRequest
    events:
      - http:
          path: /postRequest
          method: POST
```

<!-- wp:paragraph -->
<p>The post body our API accepts is of the following type</p>
<!-- /wp:paragraph -->


```json
// POST BODY TO THE API
{
   "name":"aseem"
}
```

<!-- wp:paragraph -->
<p>We will create a new endpoint called <code>postApiGateway</code> which is also of the type <code>AwsApiGatewayEvent</code></p>
<!-- /wp:paragraph -->


```dart
Handler<AwsApiGatewayEvent> postApiGateway=(context,event) async {
   final requestBody = event.body;
   final requestModel = postRequestModelFromJson(requestBody);
   final responseBody = ResponseModel(
     message: 'Hello ${requestModel.name} from AWS Lambda!!',
   );
   final response = AwsApiGatewayResponse(
      body: responseModelToJson(responseBody),
      isBase64Encoded: false,
      statusCode: HttpStatus.ok,
      headers: {
        "Content-Type": "application/json",
      },
   );
   return response;
};
```

<!-- wp:list -->
<ul><li>We extract the request body from the <code>event</code> convert it into a model and extract the name parameter.</li><li>We create <code>ResponseModel</code> with the message parameter.&nbsp;</li><li>Finally, we convert the model into JSON and send it back as <code>AwsApiGatewayResponse</code>&nbsp;</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Inside our <strong>main dart, </strong>we register our post handler as</p>
<!-- /wp:paragraph -->

```dart
Runtime()
..registerHandler<AwsApiGatewayEvent>("main.hello", helloApiGateway)    
..registerHandler<AwsApiGatewayEvent>(
      "main.postRequest",
      PostRequest().postApiGateway,
)
..invoke();
```

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: We specify <code>main.postRequest</code> (which is the same as specified inside the <code>serverless.yml</code>)</p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3>Deploy lambda on&nbsp;AWS</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Till now, we have created our lambda function using dart. Now it’s time to deploy it.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Note: Make sure docker is running on your machine</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will create a <code>Makefile</code> and inside it put</p>
<!-- /wp:paragraph -->

```makefile
.PHONY: build clean deploy
deploy:
 npx serverless deploy
remove:
 npx serverless remove
```

<!-- wp:paragraph -->
<p>For deploying the lambda, we can call </p>
<!-- /wp:paragraph -->

```makefile
make deploy
```

<!-- wp:paragraph -->
<p>If everything was successful, you should see something like this</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*_KnG2B4_NMe9n0khA0Pr7A.png" alt="Lambda deployed successfully!!"/><figcaption>Lambda deployed successfully!!</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>For removing the lambda, we can call</p>
<!-- /wp:paragraph -->

```makefile
make remove
```

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: In case you don’t want to create a makefile, simply run <code>npx serverless deploy</code></p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p><a rel="noreferrer noopener" href="https://t264fzf6eh.execute-api.us-east-1.amazonaws.com/dev/hello" target="_blank"><em>Dart Lambda Get endpoint</em></a>

<!-- wp:paragraph -->
<p><a rel="noreferrer noopener" href="https://github.com/AseemWangoo/flutter_programs/blob/master/dart_lambda.zip" target="_blank"><em>Source code.</em></a>

{% youtube YPBaruL2JRc %}

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>