-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from HubSpot/update-readme
Update readme
- Loading branch information
Showing
1 changed file
with
160 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,47 @@ | ||
# slack-client | ||
# slack-client | ||
|
||
An asychronous HTTP client wrapping Slack's [RPC-style web api](https://api.slack.com/web). The API here is simple: you just need a `SlackClient` and you're good to go. | ||
![license](https://img.shields.io/github/license/HubSpot/slack-client.svg?style=social) | ||
![GitHub last commit](https://img.shields.io/github/last-commit/HubSpot/slack-client.svg?style=social) | ||
[![Build Status](https://travis-ci.org/HubSpot/slack-client.svg?branch=master)](https://travis-ci.org/HubSpot/slack-client) ![GitHub release](https://img.shields.io/github/release/HubSpot/slack-client.svg) ![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/com/hubspot/slack/slack-client/maven-metadata.xml.svg) | ||
|
||
* [Overview](overview) | ||
* [Usage](usage) | ||
* [Setting up Guice](setting-up-guice) | ||
* [Using the Client](using-the-client) | ||
* [Find a user by email, then send a message](find-a-user-by-email-then-send-a-message) | ||
* [Filtering messages in a QA environment to specific channels](filtering-messages-in-a-qa-environment-to-specific-channels) | ||
* [Printing requests for specific methods](printing-requests-for-specific-methods) | ||
|
||
|
||
## Overview | ||
|
||
An asychronous HTTP client wrapping Slack's [RPC-style web api](https://api.slack.com/web). Provides an extensible API with builder-style parameters and responses, allowing you to focus on your interactions with users, rather than your interactions with Slack. Notably, we: | ||
|
||
* Implement most (if not all) of Slack's [web API](https://api.slack.com/web), and actively maintain this project | ||
* Provide per-method in-memory rate limiting so you don't have to worry about overwhelming slack from a single process | ||
* Expose highly configurable hooks to allow filtering and debugging in an extensible way | ||
|
||
## Usage | ||
|
||
Include the base and client modules in your POM: | ||
To use with Maven-based projects, add the following dependencies:: | ||
|
||
```xml | ||
<dependency> | ||
<groupId>com.hubspot.slack</groupId> | ||
<artifactId>slack-base</artifactId> | ||
<version>1.0</version> | ||
<version>{latest version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.hubspot.slack</groupId> | ||
<artifactId>slack-java-client</artifactId> | ||
<version>1.0</version> | ||
<version>{latest version}</version> | ||
</dependency> | ||
``` | ||
|
||
Latest version can be seen [here, on Maven central](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.hubspot.slack%22). | ||
|
||
### Seting up Guice | ||
|
||
Install the `SlackClientModule` in the Guice module you want to use to talk to slack. | ||
|
||
```java | ||
|
@@ -52,11 +75,142 @@ public class MySlacker { | |
) { | ||
this.slackClient = clientFactory.build( | ||
SlackClientRuntimeConfig.builder() | ||
.setTokenSupplier(() -> "your token here") | ||
// ... all your configuration here | ||
.build() | ||
); | ||
} | ||
|
||
// then just use the client! | ||
} | ||
``` | ||
|
||
### Using the Client | ||
|
||
If you're not familiar with Java 8's `CompletableFuture` API, know that you can transform this client from an asynchronous one to a synchronous one by calling `join` on any of the futures returned. To simplify getting started, here are some examples of using the client for common tasks. | ||
|
||
#### Find a user by email, then send a message | ||
|
||
```java | ||
void sendMeAMessage() { | ||
Optional<SlackUser> meMaybe = findMe(); | ||
if (!meMaybe.isPresent()) { | ||
LOG.error("Couldn't find me in slack!"); | ||
} | ||
|
||
slackMe(meMaybe.get()); | ||
} | ||
|
||
Optional<SlackUser> findMe() { | ||
/** | ||
* Since we may have to enumerate a large set, we chunk it up into pages, and handle each page separately. | ||
*/ | ||
Iterable<CompletableFuture<Result<List<SlackUser>, SlackError>>> userPageFutures = slackClient.listUsers(); | ||
|
||
/** | ||
* We'll enumerate the pages so we can short-circuit and break out early if we can | ||
*/ | ||
for (CompletableFuture<Result<List<SlackUser>, SlackError>> userPageFuture : userPageFutures) { | ||
Result<List<SlackUser>, SlackError> pageResult = userPageFuture.join(); | ||
|
||
// If there was a problem fetching the page, it'll percolate here as a RTE | ||
List<SlackUser> slackUsers = pageResult.unwrapOrElseThrow(); | ||
Optional<SlackUser> matchingUser = slackUsers.stream() | ||
.filter(user -> | ||
user.getProfile() | ||
.flatMap(UserProfile::getEmail) // flatMap just says the profile could be absent, or the email could be absent | ||
.filter("[email protected]"::equalsIgnoreCase) // keep it only if it's the email we want... | ||
.isPresent()) // and we'll filter the original SlackUser list to find the one with the profile that's me! | ||
.findFirst(); | ||
|
||
if (matchingUser.isPresent()) { | ||
return matchingUser; | ||
} | ||
} | ||
|
||
return Optional.empty(); | ||
} | ||
|
||
ChatPostMessageResponse slackMe(SlackUser me) { | ||
Result<ChatPostMessageResponse, SlackError> postResult = slackClient.postMessage( | ||
ChatPostMessageParams.builder() | ||
.setText("Hello me! Here's a slack message!") | ||
.setChannelId("a fancy channel ID here") | ||
.build() | ||
).join(); | ||
|
||
return postResult.unwrapOrElseThrow();// again, release failure here as a RTE | ||
} | ||
``` | ||
|
||
#### Filtering messages in a QA environment to specific channels | ||
|
||
```java | ||
public class MySlacker { | ||
private final SlackClient slackClient; | ||
|
||
public MySlacker( | ||
SlackWebClient.Factory clientFactory | ||
) { | ||
this.slackClient = clientFactory.build( | ||
SlackClientRuntimeConfig.builder() | ||
.setTokenSupplier(() -> "your token here") | ||
.setMethodFilter( | ||
new SlackMethodAcceptor() { | ||
@Override | ||
public String getFailureExplanation(SlackMethod method, Object params) { | ||
return "Only allow WRITE methods to our special channel in QA!"; | ||
} | ||
|
||
@Override | ||
public boolean test(SlackMethod slackMethod, Object o) { | ||
if (isQa() && slackMethod.getWriteMode() == MethodWriteMode.WRITE) { | ||
if (o instanceof HasChannel && ((HasChannel) o).getChannelId().equals("snazzy id")) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
}) | ||
// ... all your configuration here | ||
.build() | ||
); | ||
} | ||
|
||
// then just use the client! | ||
} | ||
``` | ||
|
||
#### Printing requests for specific methods | ||
|
||
```java | ||
public class MySlacker { | ||
private final SlackClient slackClient; | ||
|
||
public MySlacker( | ||
SlackWebClient.Factory clientFactory | ||
) { | ||
this.slackClient = clientFactory.build( | ||
SlackClientRuntimeConfig.builder() | ||
.setTokenSupplier(() -> "your token here") | ||
.setRequestDebugger( | ||
new RequestDebugger() { | ||
@Override | ||
public void debug(long requestId, SlackMethod method, HttpRequest request) { | ||
if (method == SlackMethods.chat_postEphemeral) { | ||
LOG.info("Posting ephemeral message {}", format(request)); | ||
} | ||
} | ||
} | ||
) | ||
// ... all your configuration here | ||
.builder() | ||
.build() | ||
); | ||
} | ||
|
||
// then just use the client! | ||
} | ||
``` | ||
``` |