Last week I was playing around with writing some custom Slack slashcommands and cronjobs. Originally, I started writing these integrations with PHP. Since slack requires a publically available endpoint and I did not want to set up a server for these scripts, I decided to take a look at AWS Lambda. This Amazon service makes it possible to run scripts serverless. The scripts are triggered based on triggers inside of AWS. In this artile you can find out how to get started with writing lambda functions.
Selecting the right tools
AWS Lambda can run Python, Java and NodeJS scripts. Since I've got some experience writing NodeJS, I've choosen to go for this technology. There are many tools available for writing Lambda functions in NodeJS. After investigating these tools, I've decided to go with lambda-tools. This tool makes it easy to develop and deploy multiple lambda functions inside one codebase. It comes with a Yeoman generator named generator-lambda-tools.
Getting started
The first thing we'll want to do is scafold the application:
When the command is finished, you'll find a project structure like this:
There are 2 hidden configuration files named `.lambda-tools-rc.json` and `.yo-rc.json`. These are used to configure the yeoman generator and the lambda-tools command. The `api.json` is used for the AWS API Gateway service. This service will make it possible to create a public endpoint that triggers the Lambda method we'll create next.
The `cf.json` is used for the AWS CloudFormation service. This service will take care of orchestrating the related AWS services. It will be used to deploy your lambda functions and let all the AWS services talk to each other.
The `lambdas` directory is currently empty, but will contain all the lambda functions you are going to write.
Finally there is the `node_modules` directory which contains all your project dependencies.
Writing your first lambda
The command above will create a folder named `mylambda` inside the `lambdas` directory. In this folder there are 2 files: `event.json` and `index.js`. The event.json contains the data that will be used as input for the Lambda function. Feel free to put it in `.gitignore` since you can only use this for testing purpose. The `index.js` file contains a `handler()` method and looks like this:
The callback has 2 parameters: `event` which will be populated by AWS Lambda. During development this parameter can be linked to the `event.json` file. `context` which will make it possible to `succeed()` or `fail()` the lambda method. The parameters added to these 2 functions will be returned as result of the lambda:
Creating a cronjob
In AWS CloudWatch, it is possible to create RATE or CRON rules. These rules can be the trigger for a Lambda function to execute. This means it is possible to create a lambda function that executes periodically. The generated code looks and behaves exactly the same as the `mylambda` code above. In the `cf.json` file, a event rule is added to cloudwatch and the event is linked to the lambda function.
Creating an API endpoint
By adding an API endpoint, you can create a publically available HTTPS endpoint that triggers a Lambda function. The generated code again looks the same as the `mylambda` code. The `api.json` file is altered and now describes the new endpoint:
The added path describes the endpoint. As you can see it only handles POST requests with a content-type of `application/json`. The JSON body of the request is added as the "body" parameter of the Lambda event. This is done internally through the `x-amazon-apigateway-integration` header. In the response you'll have to add the responseTemplate to make sure that the result of the lambda is returned as JSON. You can test the API endpoint with following commands:
This HTTP request will be handled as followed:
Configuring AWS
Now that we've created our lambda methods, the next step is to deploy them to AWS. This step is not documented very good, so I'll try to describe it as good as possible.
First you'll need to create a user with the IAM-permissions described on the lambda-tools page. When you've created this user, you'll have to make sure that the user has an Access Key so that it can be used to automate stuff. Now that you've got both the Access Id and Secret Access Key, you'll have to generate an API token:
Now that we have all the AWS parameters, we'll need to create a `.env` file so that the tool knows how to deploy the application:
Finally we need to configure a AWS S3 bucket in which the lambda functions will be stored. This needs to be a unique index which can be configured in the `.lambda-tools-rc.json` file. Add following `tools` to the root element:
Now that we've configured the project source code to run with AWS, we'll have to set up everything in AWS. Luckilly this can be done with one simple command that only needs to run once:
Deploying your lambdas to AWS
By running the command above, the lambdas are build into some archive files. These archive files are stored in your AWS S3 Bucket. When this is done, the `cf.json` file is added to AWS CloudFormation which will start the orchestration of the installation:
- A CloudFormation stack will be created or updated based on the `cf.json` file.
- The source code of the lambdas are stored in your S3 Bucket
- IAM permissions will be added
- A new scheduling rule will be added to CloudWatch.
- New logging groups will be added to CloudWatch.
- The API gateway will be configured with the `api.json` file.
- The lambdas will be created and configured.
Adding configurable variables to the lambdas
Adding custom configuration to a lambda function can be done based on environment variables. These variables can be added with the `-e` option during a deploy. When you've got a lot of configurable variables, another option is to add a .env file to every lambda directory and use the env-loader. You'll have to create an asset to make sure the .env file is added to your lambda source code. This can be done by adding a new `cf.json` file to every lambda directory that looks like:
Conclusion
If you are writing your first AWS project, getting started is pretty complex. The documentation is rather big and you'll have to find your way in all the different AWS services. Once you found your way and got your project set-up and configured, writing Lambda functions is pretty fun. They are easy to understand and there are a lot of NPM packages available for Rapid Application Development. I am definitely looking forward in writing more Lambda integrations!