DEV Community

Cover image for Dart on AWS Lambda
aseem wangoo
aseem wangoo

Posted on

Dart on AWS Lambda

In case it helped :)
Pass Me A Coffee!!

We will cover briefly:

  1. Dart runtime for AWS Lambda
  2. Write lambda (using Dart)
  3. Adding a POST endpoint
  4. Deploy lambda on AWS

Dart runtime for AWS Lambda

With the introduction of custom AWS Lambda runtimes, it is possible to implement a runtime in any programming language.

AWS Lambda provides an HTTP API for custom runtimes to receive invocation events and send response data back within the Lambda execution environment.

Using the custom AWS Lambda runtime, we can also run Dart on Lambda with the recently published runtime for the Dart programming language. 

  • AWS released a pub package aws_lambda_dart_runtime that packages the dart runtime to build lambda functions with AWS events.
  • It shows two ways to deploy the dart based lambda functions

Dart based lambda
Dart based lambda

In this article, we will go with the Serverless Framework approach

Write lambda (using Dart)

Pre-Requisite: You should have the aws cli configured in your machine. Check here

We will make use of the serverless framework to write lambda functions.

As per the docs,

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.

Serverless allows us to focus on the code, while it takes care of the setting up policies, and provisioning of required infrastructure onto AWS.

To install serverless, follow here. Personally, I configured using the below

npm install -g serverless
Enter fullscreen mode Exit fullscreen mode

Setup for Dart

  • Currently, serverless has no support for dart, but there is a serverless plugin for Dart applications, called serverless-dart We will install serverless-dart using
npm i -D serverless-dart
Enter fullscreen mode Exit fullscreen mode
  • Now, this plugin builds the dart lambda using docker, hence we also need to install docker

Note: In case something goes wrong, try installing the serverless framework, see above.

Create a Dart Project

Once the above setup is configured, it’s time to create a dart project. We make use of the below

npx serverless install \
  --url https://github.com/katallaxie/serverless-aws-dart \
  --name hello
Enter fullscreen mode Exit fullscreen mode

This will download the source of a sample Dart application and unpack it as a service named hello in a directory called hello

Structure of the application
Structure of the application
  • I didn’t need the .github/workflows hence, deleted the folder.
  • If we look into pubspec.yaml we will see the package aws_lambda_dart_runtime and build_runner under dev dependencies. We give both a version number.
dependencies:
  aws_lambda_dart_runtime: ^1.1.0
dev_dependencies:
  build_runner: ^2.1.0
Enter fullscreen mode Exit fullscreen mode

Next, we look into the serverless.yml which is the brain behind this application. We modify the yml file with this

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
Enter fullscreen mode Exit fullscreen mode

service: Name of the service (hello in our case)

functions: The functions to be exposed, along with their entry points. We currently have a function called hello Inside that, we specify the different configurations.

handler: This is the AWS registered handler and should be the same as inside our main.dart 

events: The events that trigger this function. This includes http

http: REST API endpoint (API Gateway v1)

path: Path for this endpoint/hello and method being GET

Note: For detailed description: see here

Inspecting the main dart

We are left with one important file to inspect main.dart . We will change the contents of the file to below

// IMPORT OMITTED FOR BREVITY
void main() async {
 Handler<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<AwsApiGatewayEvent>("main.hello", helloApiGateway)
..invoke();
}
Enter fullscreen mode Exit fullscreen mode
  • Every dart program begins with the call to mainfunction.
  • The methods such as Handler, Runtime, etc are present inside the aws_lambda_dart_runtime package.

HelloApiGateway

We define a helloApiGateway which is the handler to be invoked once our API gets hit. This is of the type AwsApiGatewayEvent and exposes two important fields: Context and AwsApiGatewayEvent 

  • The Context contains the Lambda execution context information. It comprises various parameters such as requestId etc.
  • AwsApiGatewayEvent is one of the events supported by the package. An Event is basically an abstraction for every event that can be ingested by a handler. It comprises of implementations such as AwsCognitoEvent , AwsS3Event , AwsKinesisDataStreamEvent etc

In our case, we register the event of type AwsApiGatewayEvent Hence, we can extract the details out of the incoming request. These details include headers , body , queryStringParameters etc

  • Finally, for sending the response back to the client, we make use of AwsApiGatewayResponse 
  • We specify the body to the sent, along with the additional parameters such as isBase64Encoded , statusCode and headers

Register HelloApiGateway

Once the handler is written, now we need to register it to our Runtime

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

Adding a POST Endpoint

Inside our serverless.yml add another endpoint for the post-service

functions:
  hello:
    handler: main.hello
    events:
      - http:
          path: /hello
          method: GET
  postRequest:
    handler: main.postRequest
    events:
      - http:
          path: /postRequest
          method: POST
Enter fullscreen mode Exit fullscreen mode

The post body our API accepts is of the following type

// POST BODY TO THE API
{
   "name":"aseem"
}
Enter fullscreen mode Exit fullscreen mode

We will create a new endpoint called postApiGateway which is also of the type AwsApiGatewayEvent

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;
};
Enter fullscreen mode Exit fullscreen mode
  • We extract the request body from the event convert it into a model and extract the name parameter.
  • We create ResponseModel with the message parameter. 
  • Finally, we convert the model into JSON and send it back as AwsApiGatewayResponse 

Inside our main dart, we register our post handler as

Runtime()
..registerHandler<AwsApiGatewayEvent>("main.hello", helloApiGateway)    
..registerHandler<AwsApiGatewayEvent>(
      "main.postRequest",
      PostRequest().postApiGateway,
)
..invoke();
Enter fullscreen mode Exit fullscreen mode

Note: We specify main.postRequest (which is the same as specified inside the serverless.yml)

Deploy lambda on AWS

Till now, we have created our lambda function using dart. Now it’s time to deploy it. 

Note: Make sure docker is running on your machine

We will create a Makefile and inside it put

.PHONY: build clean deploy
deploy:
 npx serverless deploy
remove:
 npx serverless remove
Enter fullscreen mode Exit fullscreen mode

For deploying the lambda, we can call 

make deploy
Enter fullscreen mode Exit fullscreen mode

If everything was successful, you should see something like this

Lambda deployed successfully!!
Lambda deployed successfully!!

For removing the lambda, we can call

make remove
Enter fullscreen mode Exit fullscreen mode

Note: In case you don’t want to create a makefile, simply run npx serverless deploy

Dart Lambda Get endpoint

Source code.

In case it helped :)
Pass Me A Coffee!!

Top comments (0)