Skip to content

coin-au-carre/slacking

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Slacking - Be lazy and send messages easily in Slack with C++

Language Standard License Build Status Build status GitHub version Slack Channel

Simple C++ Slack API

Slacking is a lightweight C++11 header only library (only two header files !) for communicating with the Slack Web API.
Slacking aims to be easy to use and stick to the API style proposed by Slack. Slacking requires to have an API token.

Requirements

No special requirement. You should already have these :

  • C++11 compatible compiler. Tested with Clang (3.5, 3.6, 3.7), GCC (4.9, 5), MSCV (VS 14 2015, VS 15 2017)
  • libcurl

Note: Slacking uses Nlohmann Json which is available in include/json.hpp

Installation

Just copy the include/slacking folder in your project and you can #include "slacking.hpp" to your code. That's all.

Example usage

Initialize a slack instance

auto& slack = slack::create("xxx-xxx-xxx-xxx"); // "xxx-xxx-xxx-xxx" is your Slack API token
slack.chat.channel = "#general"; // set a default channel

Sending a message in Slack is easy (preview)

slack.chat.postMessage("Hello there!"); // will send the message "Hello there!" in the channel #general with the registered token

Note that we try to stick with the Slack API documentation: the chat.postMessage syntax is easily recognizable.

Sending a message with a specified channel, username and icon (preview)

slack.chat.channel_username_iconemoji("#superchannel", "Ghost Bot", ":ghost:");
slack.chat.postMessage("Slacking is simple"); // will send the message "Hello there!" in the channel #general with the registered token

Note that theses changes are persistent inside the slack instance.

Sending complex messages (functionnal approach) (preview)

If you need maximum control, you can use the generic functions slack::post or slack::get.
Everything available in Web Slack API is possible from here.

slack::post (   
    "chat.postMessage",
    {
        {"text"      , "Slacking is awesome!" },
        {"channel"   , "#mychannel"           },
        {"username"  , "peach"                },
        {"icon_emoji", ":princess:"           }
    } // note that "token" is not needed here and is a "registered" parameter
); // it is automatically inserted when using slack::post()

Sending complex messages (JSON approach) (preview)

If you prefer to mimic the JSON approach given in the API, you can also use this syntax:

 auto json = R"({
    "text":         "But Our Princess is in Another Castle!",
    "channel":      "#general",
    "username":     "peach",
    "icon_emoji":   ":princess:"
})"_json;

slack::post("chat.postMessage", json);

Check out the examples for more illustrations.

A more elaborated example (preview)

You can make richly-formated messages with attachments.

slack.chat.channel_username_iconemoji("#ticker-channel", "Support Bot", ":hamster:");

auto json_attachments = R"([
    {
        "fallback": "New ticket from Bjarne Stroustrup - Ticket #2017: Still looking for reflection",
        "pretext": "New ticket from Bjarne Stroustrup",
        "title": "Ticket #2017: Still looking for reflection",
        "title_link": "https://www.youtube.com/watch?v=ND-TuW0KIgg",
        "text": "Help me adding reflection!",
        "color": "#7CD197",
        "image_url": "https://img.youtube.com/vi/ND-TuW0KIgg/2.jpg"
    }
])"_json;

slack.chat.attachments = json_attachments;
auto response = slack.chat.postMessage(); // get a slack::Json object
std::cout << response << std::endl;

Slacking attachments

The output received is a JSON response sent back by the Slack API:

{"channel":"C1AUF9AN4","message":{"attachments":[{"color":"7CD197","fallback":"New ticket from Bjarne Stroustrup - Ticket #2017: Still looking for reflection","id":1,"image_bytes":4820,"image_height":90,"image_url":"https://img.youtube.com/vi/ND-TuW0KIgg/2.jpg","image_width":120,"pretext":"New ticket from Bjarne Stroustrup","text":"Help me adding reflection!","title":"Ticket #2017: Still looking for reflection","title_link":"https://www.youtube.com/watch?v=ND-TuW0KIgg"}],"bot_id":"B20LJ4Y12","icons":{"emoji":":hamster:","image_64":"https://slack.global.ssl.fastly.net/d4bf/img/emoji_2015_2/apple/1f439.png"},"subtype":"bot_message","text":" ","ts":"1464251666.000063","type":"message","username":"Support Bot"},"ok":true,"ts":"1464251666.000063"}

Since Slack::Json is a typedef to a nlohmann::json, you have all the features of the latter one (conversions, STL like access, ...). For instance, response["ok"] will give true.

A word about error handling

By default, Slacking will throw a runtime error exception if the curl request does not succeed, if the response from Slack is not correct, or if response["ok"] received is not true. You are free to handle these exceptions the way you like.

Since 0.2, you are now able to prevent throw exceptions by setting false to these functions slack::create("xxx-xxx", false) or slack.set_throw_exception(false). If you do that, a warning will be displayed and you won't have to try/catch every postMessage for instance if you want to avoid brutal stops in your program.

Ongoing work

You can use the slack::post or slack::get methods to fully exploit the Slack Web API methods. You can refer to examples/06-custom_post_get.cpp.cpp.

Following C++ helpers free functions and member methods are available in Slacking for convenience :

Try out the "magic" functions for grabbing ready-to-use structures. This is an ongoing work so more convenient helpers functions and structures might come in the near future...
If you need any features feel free to ask and contribute.

Manage Slacking instance

Here are two approaches to keep alive the Slacking session in your program so you can use it anytime, anywhere.

Use Meyers singleton

Slacking provides free convenient functions : slack::create(const std::string& token) and slack::instance(). Initialize the Slacking instance with:

auto& slack = slack::create("xxx-xxx-xxx-xxx");

And when you are in another scope and you have lost the slack reference, you can grab it again with :

auto& slack = slack::instance();

It might not be the recommended way but since we generally want to handle only one Slack instance (one token), it is highly convenient. You can refer to the example usage and examples/01-basic.cpp.

Pass by reference (or by pointer)

An other approach is to pass the Slacking instance by reference, store it, and call the appropriate methods when needed.

void foo(slack::Slacking& slack) {
    slack.chat.postMessage("I am slacking!", "#random");
}

int main() {
    slack::Slacking slack_instance{"xxx-xxx-xxx-xxx"};
    foo(slack_instance);
}

You can use a std::reference_wrapper as shown in examples/02-basic.cpp. This strategy is useful if you have to manage several Slacking instances.

Build the examples

mkdir build && cd build
cmake .. && make
examples/[whatever]

In your project, if you want a verbose output like when running the examples, add the following compilation flag:
-DSLACKING_VERBOSE_OUTPUT=1.

Note for Windows users

You might have difficulties handling libcurl where CMake throws Could NOT find CURL (missing: CURL_LIBRARY CURL_INCLUDE_DIR).

One way to solve this is to grab the curl version for Windows here, copy the content of include in appropriate folders available visible in your PATH (e.g. if in your Git installation [...]/Git/mingw64/include/). You also need to grab the curl.lib and the libcurl.dll files from here and copy them in appropriate folders (e.g. if in your Git installation [...]/Git/mingw64/lib/).

mkdir build && cd build
cmake .. -DCMAKE_GENERATOR_PLATFORM=x64
cmake --build .
cmake --build . --target 00-showcase # For a specific target

Or if you prefer using GNU GCC on Windows

cmake -G "MSYS Makefiles" -D CMAKE_CXX_COMPILER=g++ ..
make