Serverless Discord Bot on AWS in 5 Steps | by jakjus | May, 2022

Body-based routing in AWS API Gateway using Proxy Lambda — with AWS SAM

Photo by Alexander Shatov on Unsplash

In my previous article, we built a Discord bot using AWS Lambda. We clicked through everything in AWS Portal, and it was all good. We have set up an API Gateway and the “hello world” Lambda.

But I’ve hidden one little detail.

Making a serverless application means creating one lambda function for each duty — it’s called Single Responsibility Principle. In the article, we had just one responsibility. Take a look:

Now, imagine we add a second function to this file. And a third one. Cool. And these functions, probably, don’t simply reply with a string, but rather perform some rendering/calculations/whatever. And they become larger. Great.

Now we have implemented a main anti-pattern for Serverless — the Lambda Monolith.

We want to handle different Discord user interactions by delegating each interaction to different Lambda. The problem is… Discord sends all the events to one endpoint. API Gateway can natively route requests to Lambda’s based on request header and paths, but routing by request body requires using Template Mapping which is not easy, and it is limited.

We need something to proxy the request.

We will use Proxy API Gateway and Proxy Lambda to handle requests going to / path (Proxy part). Then, we will route it to SNS Topic with a special parameter that will further split events into Main Lambdas.

Our solution’s architecture

This architecture:

  1. Makes Proxy Lambda run only during routing.
    Proxy Lambda is not being run when Main Lambda handles requests (as it would happen with nested Lambdas).
  2. Decouples Proxy and Main parts.
    It helps in the development, testing, and migration from other Serverless applications (ie, not Discord).
  3. Makes Proxy Lambda an ideal place to put Discord request verification into.

Data flow:

  • User sends /hello on Discord Channel
  • Discord App Server sends an event to your Proxy API Gateway URL (set in settings)
  • Proxy API Gateway sends an event to Proxy Lambda
  • Proxy Lambda verifies requests and responds to Discord App Server with a temporary response “Loading…” to be shown while the main function runs. Sets MessageParameter to invoke a command name for further handling.
  • Simple Notification Service (SNS) receives an event. Handles event with appropriate Lambda, based on MessageParameter.
  • (Single Responsibility) Lambda handles an event and sends a POST request with the content “Hello from Lambda!” back to Discord App Server’s webhook.
  • Discord App Server edits response to /hello on Discord Channel from “Loading…” to “Hello from Lambda!”.

We will build this app using Infrastructure as Code tool with AWS SAM and a template from a git repository. Once you will have this boilerplate cloned, it will be easy for you to go further and beyond with your own Lambda’s.

Never heard of AWS SAM? Find a quick recap in my other article.


1. Create Discord application

Go to Discord Developer Portal → New Application.

Bot → Add Bot.

Invite the bot to your guild (OAuth2 menu) with Bot, applications.commands , Use Application Commandsand Send Messages privileges.

(additional help)

2. Register commands

Get your development Guild (Discord Server) Id by enabling Developer Mode in settings and right-clicking your guild.

Get App Id and Bot Token from Discord Developers Portal.

Then, register commands on one guild for development (instant):

node register_commands/register.js --env dev --guild-id YOUR_GUILD_ID --bot-token YOUR_BOT_TOKEN --app-id YOUR_APPLICATION_ID

3. Clone the boilerplate

mkdir serverless-discord-bot && 
cd serverless-discord-bot &&
sam init --location gh:jakjus/serverless-discord-bot

4. Build and deploy the application on AWS

sam build && sam deploy --guided

Every answer can be a default one (just press enter), except:

  1. When prompted for DiscordAppPublicKeypaste the key from Step 1.
  2. When prompted [Some function] may not have authorization defined, Is this okay? , answer with y

5. Set Discord Webhook URL

The previous command shows you:

------------------------------------------Outputs------------------------------------------Key                 ProxyGWEndpointDescription         API Gateway endpoint URL to pass 
to Discord Application Portal

The output’s description says it all.

Copy the URL, and paste it back into Discord Developer Portal’s “Interaction Endpoint URL” field.

Interactions endpoint URL field.

Click Save Changes.

Say /hello to your brand new bot.

Discord Guild chat. Interacting with Slash Command.

The bot will reply with the following:

The power of Infrastructure as a Code, right?

Make the function do something else

  1. Change the code in src/handlers/hello-from-lambda.js
  2. Run sam build && sam deploy
    If you saved input values ​​during --guided run, you can then run it without this flag to reuse values.

Add your own function

  1. Add a command in register_commands/commands.yaml and register it again.
  2. Create a handler for new function in src/handlers/ similar to hello-from-lambda.js.
  3. Add a reference to new handler in template.yaml similarly to helloFromLambdaFunction. Change Properties.Handler and Events.SNSEvent.Properties.FilterPolicy.command.

Clean up

All of these resources are in the free tier. It’s still nice to not forget to clean your resources with:

sam destroy

after you’re done.

In this article you have:

  • learned how to use templates in AWS SAM
  • comprehended specified serverless architecture and its reasoning
  • a full-stack serverless application on AWS that listen for events forever
  • and ever
  • or until your credit card expires

The setup that we have performed is pretty tough to figure out at the start. That’s why AWS SAM and IaC practices make it so only one poor person has to go through all of it. The person was me in that case.

Here’s the boilerplate repository. Contributions welcome.

I’ve researched a lot for this article, but the most important question still remains.

What will you build with it?

Leave a Comment