diff --git a/README.md b/README.md
index 9528d6ab..9845efd5 100644
--- a/README.md
+++ b/README.md
@@ -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
com.hubspot.slack
slack-base
- 1.0
+ {latest version}
com.hubspot.slack
slack-java-client
- 1.0
+ {latest version}
```
+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 meMaybe = findMe();
+ if (!meMaybe.isPresent()) {
+ LOG.error("Couldn't find me in slack!");
+ }
+
+ slackMe(meMaybe.get());
+}
+
+Optional findMe() {
+ /**
+ * Since we may have to enumerate a large set, we chunk it up into pages, and handle each page separately.
+ */
+ Iterable, SlackError>>> userPageFutures = slackClient.listUsers();
+
+ /**
+ * We'll enumerate the pages so we can short-circuit and break out early if we can
+ */
+ for (CompletableFuture, SlackError>> userPageFuture : userPageFutures) {
+ Result, SlackError> pageResult = userPageFuture.join();
+
+ // If there was a problem fetching the page, it'll percolate here as a RTE
+ List slackUsers = pageResult.unwrapOrElseThrow();
+ Optional 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("eszabowexler@hubspot.com"::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 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!
}
```
+```