Reino Muhl :DEV:
Reino Muhl
Freelance Software Developer

Building a Slack enabled Contact Form

So I’ve created my website using GatsbyJS and launched it. Next up I need a standard contact form so that people can get in touch. But, instead of sending the contact form information to an email address, I want to send it to a Slack channel.

When building this, to keep my site serverless, I’ve decided to use an AWS Lambda function in between my GatsbyJS site and Slack. So the architecture will look something like this.

Creating the Form

Building the react form component is relatively straight forward and in this case I just followed the Gatsby docs.

In a future article I’ll probably convert this form component, which still uses a class component, to instead use React Hooks which were introduced in React 16.8.

Creating the AWS Lambda function

Next up, let’s create the AWS Lambda function, which will be triggered by an AWS API Gateway endpoint.

For now the Lambda function only has 2 jobs.

  • Accept the incoming contact form message.
  • Pass the message on to Slack.

Creating the AWS API Gateway and Lambda function

For the API Gateway, I just want to have one end point that allows me to POST data to the Lambda function. I was happy to find this article by Joe Seifi, that explained how to do this very well.

Even though I only had 1 endpoint, I did want to have both a development and production stage, which would call a development and production Lambda function, respectively.

The reason I wanted separate stages was so that I could test new functionality when calling the development stage, without interrupting my live production resources. Pretty standard stuff.

So once the API resource was created I had to a little more research on how to achieve this and that’s when I came across stage variables and using these to call different functions depending on which stage is called.

Right, so where are we? We have the API Gateway endpoint’s, which will be called by the Gatsby front-end, and we have the Lambda functions triggered by the API Gateway. But we aren’t sending any messages through to Slack yet.

Create a Slack App Bot.

Next up we need to create the Slack App Bot. The Slack documentation is very solid. I’d recommend starting with their “Overview” and “An introduction to apps” sections.

For my purposes I only need the Bot to post a message to a specific channel and I mostly followed the tutorial at the link below, to create the Bot and assign the appropriate scopes and permissions. In this case OAuth Scope chat:write.

https://api.slack.com/start/building/bolt

Adding logic to the Lambda function

Once the Slack App Bot is created and added to my slack channel, it’s time to add the logic to the Lambda function. Since we are creating a Node.js Lambda function, we’ll be using the Bolt for JavaScript framework as suggested by Slack.

I used the sample code provided by the link below, but ended up only keeping the pieces that I needed. The relevant keys mentioned in the code can be found on your Slack Bot’s page.

The final Node.js function can be found at the link below.

If you need any help deploying the Node function to Lambda, AWS has some very thorough documentation, linked below.

Updating Gatsby site to call API Gateway

Finally, let’s update the react contact form so that it calls the API Gateway endpoint. To do this, we simply add a call to the Fetch API in the onSubmit function.

I’ve also added some environment variables. This is useful so that when I’m busy developing, the fetch calls the development stage of the API Gateway, and when deployed to production, it calls the production stage. I’ve included a link to the Gatsby environment variables entry below.

A version of the contact form I’ve put together can be found at the link below.

Why do I even need the Lambda function?

Before ending this post with the conclusion, there’s just one more thing I’d like to address. At this point you might be thinking, isn’t the Lambda function a little overkill? Couldn’t I just call the Slack API directly from the react form component, instead of routing it through the lambda function?

If you look at this use case in isolation, yes you definitely could. Why I elected not to is primarily because of the following 2 points.

  • Security
  • Separation of concerns

By using the AWS API Gateway, I get some security benefits, like throttling, that will ensure the API calls don’t get abused.

With regards to separation of concerns, by using the lambda function, I can move all back-end functionality into the lambda function, which allows the front-end to focus on what it does best without being concerned with what happens to the contact information once it’s sent.

This approach also allows me to grow the Lambda function to do a lot more than what it does now. For example, I have plans to send out emails and maybe add an IoT device as an additional notification (Think 📯 or 🚨 going off every time the contact form is used). Best of all, by keeping the front-end and back-end separate, all the additional features are added without needing to make any changes to the front-end code.

Finally, I also get some smaller benefits like access to AWS CloudWatch, so that I can monitor all the contact requests I’ll be getting.

Conclusion

Right that’s it. The Contact component has been added to the site. Why don’t you try it out and let me know what you think. 😉

In future posts I’ll be updating the contact form to use React Hooks, exploring additional Slack Bot features I might want to use, and also look into adding more functionality to the Lambda function and hardening it a bit more.