How to publish to a Slack channel with SAS

Slack is a tremendously popular app for team collaboration. At its core, it's an open messaging app that allows team members to communicate with each other in real time. It works well with "startup"-style teamwork, which requires constant communication among people who aren't always located together. I've heard a lot about Slack from colleagues and from podcasts (Slack is a frequent advertiser on tech shows), but I'd never tried it myself until recently.

I was most curious about their APIs, which allow you to integrate other applications into the Slack messaging platform. Months ago, a colleague had asked me whether it was possible to integrate SAS output with Slack. I suspected that we could do something with PROC HTTP, but didn't get around to trying until today. I can now answer for certain: Yes! It's possible...and it's sort of fun!

Get started with a Slack "webhook"

I won't go into how you get started with Slack, except to say that it's really easy (and free) to create an account and a "channel" (your message space) for a small team. Assuming that you have that going, I'm going to show you how to use SAS to publish to your channel.

Slack supports a feature called "Incoming Webhooks," which is basically a simple endpoint URL that you can send messages to. From your Slack channel, you can select to Add Configuration, which takes you to the option to add a new Incoming Webhook:

Click the button and Slack will provision a cryptic URL that's your unique endpoint. Any process that uses HTTP calls to POST content to that URL can publish content. The content itself (called the payload) is delivered in JSON format to the API.

Example 1: Simple in-line message with PROC HTTP

The Slack documentation supplies examples that use curl (command-line URL tool), but PROC HTTP is the SAS equivalent. Here's a simple example:

%let webhookUrl = https://hooks.slack.com/services/<your Webhook URL>;

/*
Simple example with direct text
*/

filename resp temp;
proc http
url="&webhookUrl"
method="POST"
/* IN= supports text in SAS 9.4m3. Earlier release? Use fileref with content */
in='payload={"channel": "#fromsas",
"username": "sasprogram",
"text": "Created using PROC HTTP!"}'
out=resp
;
run;

To try this, you'll have to first get your own Webhook URL and plug it into the program. I'd loan you mine, but you're not on my channel so you can't check the results...which look like this:

Example 2: Share rich messages with PROC HTTP and JSON

Slack also allows multipart messages with simple formatting, including some colors, custom icons, and working links. This requires a little bit more JSON content in the payload, including an array of attachments. Here's a more complex example:

/*
More complex messages, with multiple parts.
Use the attachments fields that Slack supports
*/
filename rich temp;

data _null_;
file rich;
infile datalines4;
input;
put _infile_;
datalines4;
payload=
{
"channel": "#fromsas",
"username": "sasprogram",
"icon_emoji": ":fax:",
"attachments":[
{
"fallback":
"New SAS Dummy post!: <https://blogs.sas.com/content/sasdummy|The SAS Dummy blog>",
"pretext":
"New SAS Dummy post!: <https://blogs.sas.com/content/sasdummy|The SAS Dummy blog>",
"color":"#3030F0",
"fields":[
{
"title":"Great news!",
"value":"That Chris...he's done it again!",
"short":false
}
]
}
]
}
;;;;

proc http
url="&webhookUrl"
method="POST"
in=rich
out=resp
;
run;

Here's the result. See how I selected a nice modern emoji as the account icon? Slack has hundreds of these available.

Example 3: Data-driven JSON payload published to Slack using PROC HTTP

But the real power of this integration from SAS is the ability to push dynamic, data-driven content to your Slack channel. To accomplish that, you need to dynamically generate your JSON content with the fields that you want to share. Here's an example that publishes the output of a SAS procedure (read from a data set) to the channel:

/*
And finally an example that publishes values from data!
*/

/* Calculate some data */
proc means data=sashelp.class noprint;
var age;
output out=stats;
run;

/* file to hold the JSON payload */
filename msg temp;

/* Create the start of the JSON payload */
data _null_;
file msg ;
infile datalines4;
input;
put _infile_;
datalines4;
payload=
{
"channel": "#fromsas",
"username": "sasprogram",
"icon_emoji": ":fax:",
"attachments":[
{
"fallback":"Latest Stats for AGE in SASHELP.CLASS",
"pretext":"Latest Stats for AGE in SASHELP.CLASS",
"color":"#D000FF",
"fields":[
;;;;

/* fill in the data fields in the middle */
data _null_;
file msg mod;
set stats end=eof;
put '{ "short":false, "title": "' _stat_ '",';
put '"value": "' age '" }';
/* separate values with commas, except the last */
if not eof then put ",";
run;

/*
And finish with the tail end of the payload
*/

data _null_;
file msg mod;
infile datalines4;
input;
put _infile_;
datalines4;
]
}
]
}
;;;;

proc http
url="&webhookUrl"
method="POST"
in=msg
out=resp
;
run;

Here's the result -- the latest figures from SASHELP.CLASS!

I've shared the complete example code on a public Gist on GitHub. Remember, to try it yourself you'll need to:

Create a Slack account, if you don't have one. Along with a new Slack channel.

Use the Slack site to add a new Incoming Webhook for your channel

Replace the webhookURL macro value in my example code with your specific Webhook URL.

Have fun! And if you create anything really interesting, I hope you'll invite me to your Slack channel!