Matthew J. Clemente

Quick and Dirty CFML Slack Notifications with Hyper

May 12, 2022
4 minutes

While there may be times you need a full-featured Slack integration, just being able to send messages to a channel can be a win for many applications. I recently needed to alert a Slack channel whenever an application was deployed, and found that using Eric Peterson's module Hyper along with Slack's Incoming Webhooks did the trick nicely.

I'll share how to do this with a FW/1 application - just know that with ColdBox it would be even easier, and the general approach could even be modified to work without a framework.

Incoming Webhooks for Slack

So what are these incoming webhooks? To quote from Slack's documentation:

Incoming webhooks are a simple way to share information from external sources with your workspace.

That sounds exactly like what we're looking for. The slightly more technical tldr; is that Slack's Incoming Webhooks enable HTTP requests with a JSON payload to send a message to a channel. Note that unlike more advanced integrations, they are limited to notifying a single channel.

Slack provides a detailed guide to sending messages using Incoming Webhooks. I'm not going to reiterate it all here, since the guide really does take you through every step. You'll need to follow those instructions in order to generate the Webhook URL, which is what we need for this post. A Webhook URL looks like this:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

👉 As the docs remind you, you should treat this URL like a password or other sensitive information because it contains a secret. Don't go posting it publicly.

Now we've got the URL, but we need a way to post information to it. While we could do this with cfhttp, Hyper provides a number of conveniences that make it preferable. Let's get it set up.

Hyper Configuration

A few weeks ago posted a guide to using Hyper with FW/1, so I won't rehash the whole setup. If you're using FW/1, you'll need to go through those steps, installing the module and setting up its mapping.

Once that's in place, we can set up Hyper's configuration for this webhook in our LoadListener.cfc.

component {
function onLoad(beanFactory) {

arguments.beanFactory
.declare("slackIncomingWebhookClient")
.asValue(new hyper.models.HyperBuilder(
baseUrl = YOUR_SLACK_WEBHOOK_URL_HERE))
.done();

beanFactory.load();
}
}

What we've done here is preconfigured a singleton instance of Hyper (named slackIncomingWebhookClient) for making our HTTP requests to the Slack Incoming Webhook. All that's left to do is construct the message.

Sending the Messages to Slack

We'll build our Slack message as a CFML struct - at its most basic, it would look like this:

payload = {
"text": "Hello, world."
};

In my situation, in which I wanted to receive Slack alerts at the start of a FW/1 application's lifecycle, I added the following to my Application.cfc:

function setupApplication() {
var slackWebhook = getBeanFactory().getBean("slackIncomingWebhookClient");
var payload = { "text": "message here"};
slackWebhook.post("", payload);
}

In this code we're using DI/1 to retrieve the Hyper Slack client; we then call its post() method to send the payload. And, voilà! Just like that, Slack alerts me on application startups.

The slackIncomingWebhookClient singleton could also be injected into a beans, services, or controllers in the application, if I needed to send messages from other places in the application.

Formatting the Message

Slack provides a good deal of documentation on how you can enhance and format your messages; here's the guide to formatting, and here's a more advanced guide for creating what they refer to as "rich message layouts". You can add sections, images, attachments, and even make the messages interactive.

For example, here is a slightly more advanced message layout, defined as a payload object:

payload = {
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "I'm an example"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "This *message* ~oops~ _contains_ a URL <http://example.com/>"
}
}
]
}

The above would be rendered like this:

Slack message with header and formatted body section

For my use case, I built out a more complex message with several sections in order to provide more information about the application being deployed.

This is the first time I've connected a CFML application with Slack in any way. If you've got more full-featured integrations, I'd love to hear about them. Cheers!