Integration Between Java and Slack With Webhooks

As you probably know, Slack is one of the most common company communicators nowadays. All possible plugins, apps, and bots, which can extend its functionalities, are a hot topic recently, especially as of now when more and more companies are forced to work remotely. Through the course of this article, I will try to show how to create a simple, yet useful, integration between Java and Slack. I will use links to Slack documentation and tutorials which provide detailed description of Slack features.

What are Slack Incoming Webhooks?

Here the answer is simple but meaningful. Webhooks are an easy (probably the easiest) way to post messages from custom apps to Slack users and channels. They use JSON as messages data format, and they also allow us to use the standard Slack formatting and layout blocks.

To use them, you have to create a Slack app. I did not manage to find a properly descriptive tutorial.

I recommend to open this link https://api.slack.com/apps and click the big green button Create an AppInemodal, you will have to choose the name and workspace for the app. After creating the app, you have to enable Incoming Webhooks. On the bottom of the screen, with Webhooks enabling checkbox, you will see a button Add New Webhook to Workspace, which will allow you to get the Webhook of particular channel. Now you have to copy the last part of new Webhook. 

In the example below the part, which should be copied is marked in red:

https://hooks.slack.com/servic/T016M7S1PK4/B0187LJ9FFZ/Nw1hTMVJldSQQaXfpFYf2Y2e

If you have any troubles with configuring app Webhooks or simply want to know more about them, I recommend you to read this article. The article comes from official Slack documentation and concerns sending messages with Webhooks.

Before we start – quick disclaimer.

I know that the code quality and design of provided examples can be considered questionable. Please remember that it is a more PoC  rather than something that is ready for production.

Let’s create our app step by step

Step 1

We will need a new spring boot project as a base. chose Spring Boot as it provides plenty of configurations out of the box and has a number of modules which allow us to set up our app faster and add new features to it later on. It is also very well integrated with IntelliJ. If you do not have IntelliJ installed I recommend to use Spring Initializr. We will need only one artifact, namely, Spring Web so project configuration should not be hard for anyone.

Step 2

After the previous step, we have fully functioning Spring Boot app. Now, iis time to add something useful there. We start with creating a POJO named Message which will represent our message from the HTTP request. 

Then, we create a simple REST controller called MessageInterceptorController.

We will also create a service called MessageSender, which we will further inject into the controller. A code after this step should be more or less like this:

Java
 




xxxxxxxxxx
1
11


 
1
//imports
2
3
@RestController
4
public class MessageInterceptorController {
5
  
6
    private final MessageSender messageSender;
7
  
8
    public MessageInterceptorController(MessageSender messageSender) {
9
        this.messageSender = messageSender;
10
    }
11
}



Java
 




xxxxxxxxxx
1


 
1
//imports
2
3
@Service
4
public class MessageSender {
5
6
}



Java
 




xxxxxxxxxx
1


 
1
public class Message {
2
  
3
    private String text;
4
  
5
    public String getText() {
6
        return text;
7
    }
8
}


Step 3

Now, when we have the base of our middleware, we will add some functionalities. In the controller, we add single endpoint with @PostMapping and path /messages/{userName}The endpoint will get the value of variable userName with usage of @PathVariable and our message with help of @RequestBody

Both values will be further used to call newly created method sendMessage in MessageSenderwhich will be the most vital method of this app. After this step our code should be similar to the one from below. I did not paste the content of Message class because it remains unchanged from the previous step.

Java
 




xxxxxxxxxx
1
16


 
1
//imports
2
3
@RestController
4
public class MessageInterceptorController {
5
  
6
    private final MessageSender messageSender;
7
  
8
    public MessageInterceptorController(MessageSender messageSender) {
9
        this.messageSender = messageSender;
10
    }
11
  
12
    @PostMapping(path = "/messages/{userName}", consumes=MediaType.APPLICATION_JSON_VALUE)
13
    public void sendMessage(@PathVariable String userName, @RequestBody Message message) {
14
        messageSender.sendMessage(userName, message);
15
   }
16
}



Java
 




xxxxxxxxxx
1


 
1
//imports
2
3
@Service
4
public class MessageSender {
5
  
6
 public void sendMessage(String userName, Message message) {
7
    
8
    }
9
}



Step 4

In this step, we will add a Map, which will store the relation between a user name and the particular user channel Webhook, so the user name will be Map key and the channel Webhook will we Map value. We will also add a constant field which will store a common part of Webhooks URL. Your code after this step should be similar to the one below. Of course your user name and channel Webhook should be different then my.

Java
 




xxxxxxxxxx
1
14


 
1
//imports
2
3
@Service
4
public class MessageSender {
5
6
    private static final String HOOKS_URL = "https://hooks.slack.com/services/%s";
7
8
    private static final Map<String, String> USER_TO_CHANNEL_WEBHOOK =
9
            Map.of("Pask", "T016M7S1PK4/B0187LJ9FF/Nw1hTMVJldSQQaXfpFYf2Y2e");
10
11
 public void sendMessage(String userName, Message message) {
12
    
13
    }
14
}



Step 5

Here, we will implement sendMessage itself. Firstly, we will get the channel Webhook from our Map and create a full Webhook URL with it. Secondly we instantiate RestTemplate which will be our HTTP client. Thirdly we have to create JSON from our message. We will do it using ObjectMapper . The next thing to create HTTP Header for ContentType with value aplication/json . Then we create HttpEntity of type String and use it to call exchange method from RestTemplate which will send our request to the Slack.

Java
 




xxxxxxxxxx
1
26


 
1
//imports
2
3
@Service
4
public class MessageSender {
5
6
    private static final String HOOKS_URL = "https://hooks.slack.com/services/%s";
7
8
    private static final Map<String, String> USER_TO_CHANNEL_WEBHOOK =
9
            Map.of("Pask", "T016M7S1PK4/B0187LJ9FFZ/Nw1hTMVJldSQQaXfpFYf2Y2e");
10
11
 public void sendMessage(String userName, Message message) throws JsonProcessingException {
12
   String userChannelId = USER_TO_CHANNEL_WEBHOOK.get(userName);
13
        String userWebhookUrl = String.format(HOOKS_URL, userChannelId);
14
        RestTemplate restTemplate = new RestTemplate();
15
16
        HttpHeaders headers = new HttpHeaders();
17
        headers.setContentType(MediaType.APPLICATION_JSON);
18
      
19
        ObjectMapper objectMapper = new ObjectMapper();
20
        String messageJson = objectMapper.writeValueAsString(message);
21
      
22
        HttpEntity<String> entity = new HttpEntity<>(messageJson, headers);
23
      
24
        restTemplate.exchange(userWebhookUrl, HttpMethod.POST, entity, String.class);
25
    }
26
}



Java
 




xxxxxxxxxx
1
16


 
1
//imports
2
3
@RestController
4
public class MessageInterceptorController {
5
  
6
    private final MessageSender messageSender;
7
  
8
    public MessageInterceptorController(MessageSender messageSender) {
9
        this.messageSender = messageSender;
10
    }
11
  
12
    @PostMapping(path = "/messages/{userName}", consumes=MediaType.APPLICATION_JSON_VALUE)
13
    public void sendMessage(@PathVariable String userName, @RequestBody Message message) throws JsonProcessingException {
14
        messageSender.sendMessage(userName, message);
15
   }
16
}


Step 6

With the main functionality done, it is time for short refactor. We will focus on improving exception handling. We will also change our endpoint to return ResponseEntity object with the correct HTTP code depending on how the request will be processed.

Java
 




xxxxxxxxxx
1
11


 
1
//imports
2
3
@PostMapping(path = "/messages/{userName}", consumes = MediaType.APPLICATION_JSON_VALUE)
4
public ResponseEntity<String> sendMessage(@PathVariable String userName, @RequestBody Message message) {
5
        try {
6
            messageSender.sendMessage(userName, message);
7
            return ResponseEntity.ok().build();
8
        } catch (JsonProcessingException e) {
9
            return ResponseEntity.badRequest().build();
10
        }
11
    }



Et voila - integration done


Tests

For such simple tests, I recommend curl, but it can be also done with Postman, depending on which one you prefer. I will try to describe an example for both of them.

I will start with curl.

Here the only thing that you need is one line of script from below

Shell
 




xxxxxxxxxx
1


 
1
curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello Slack from Dzone with curl !"}' http://localhost:8080/messages/Pask



In Postman you have to choose POST as request method then copy this URL: http://localhost:8080/messages/Pask into proper field. You also have to specify the body content type with value JSON. To do so, you have to copy this string into the body tab located below URL field. As you can see i provided a screen-shot with the Postman configuration.

GET request in Postman


The last thing to do is to click the Send button. You should get a desired message on a selected Slack channel.

Notifier in Slack

Now our integration has been tested.


Ideas How To Make It Better

1. As for now the list of channels’ Webhooks is static and requires a new deployment to update. Here it is the first place to make our middleware better. For example we can use the properties file, a simple text file or even a database. H2 will be extremely useful here (remember to encode Webhooks).

2. Add an endpoint for sending a message to many users from one request

3. Put the common part of Webhook URL in Spring Boot application.properties file


Summing up

That is all for today. Thanks for your time. I hope that you find this example useful and it will give you some new ideas on how to make Slack integrations.

 

 

 

 

Top