From 9b2afd2e8007c5c1e4f97d8934641085751a54e1 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 14 Jul 2026 16:27:53 -0700 Subject: [PATCH 1/3] feat(methods): add chat.postMessage example Add a methods/ example module demonstrating individual Slack Web API method calls with slack-api-client, starting with chat.postMessage. The example mirrors the canonical docs snippet (MethodsClient + ChatPostMessageRequest.builder()), and a MockWebServer test verifies the request hits chat.postMessage with the expected channel and text. Also lists the methods set in the repo README. Co-Authored-By: Claude --- README.md | 1 + methods/.gitignore | 4 + methods/README.md | 21 +++++ methods/pom.xml | 81 +++++++++++++++++++ .../src/main/java/chat/ChatPostMessage.java | 38 +++++++++ .../test/java/chat/ChatPostMessageTest.java | 51 ++++++++++++ 6 files changed, 196 insertions(+) create mode 100644 methods/.gitignore create mode 100644 methods/README.md create mode 100644 methods/pom.xml create mode 100644 methods/src/main/java/chat/ChatPostMessage.java create mode 100644 methods/src/test/java/chat/ChatPostMessageTest.java diff --git a/README.md b/README.md index 18d2e26..725365d 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,4 @@ This collections of examples highlights features of a Slack app in the language ## Available demonstration - **[Block Kit](./block-kit)**: The framework of visual components arranged to create app layouts. +- **[Methods](./methods)**: Individual Slack Web API method calls with the `slack-api-client`. diff --git a/methods/.gitignore b/methods/.gitignore new file mode 100644 index 0000000..beef00d --- /dev/null +++ b/methods/.gitignore @@ -0,0 +1,4 @@ +.classpath +.project +.settings +target diff --git a/methods/README.md b/methods/README.md new file mode 100644 index 0000000..ac32962 --- /dev/null +++ b/methods/README.md @@ -0,0 +1,21 @@ +# Methods + +Individual Slack Web API method calls with the `slack-api-client`. + +Read the [docs](https://docs.slack.dev/reference/methods) to explore every method, or explore implementations of specific families. + +## What's on display + +### chat + +- **[chat.postMessage](https://docs.slack.dev/reference/methods/chat.postmessage)**: Sends a message to a channel. [Implementation](./src/main/java/chat/ChatPostMessage.java). Scopes: `chat:write`. + +## Running an example + +Set a bot token and run an example class directly: + +```sh +export SLACK_TOKEN="xoxb-your-token" +mvn compile exec:java -Dexec.mainClass=chat.ChatPostMessage +``` + diff --git a/methods/pom.xml b/methods/pom.xml new file mode 100644 index 0000000..32dbcc1 --- /dev/null +++ b/methods/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + com.slack.api + methods-examples + 0.1-SNAPSHOT + jar + + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.15.0 + + 17 + + + + com.diffplug.spotless + spotless-maven-plugin + 3.7.0 + + + + + .gitignore + + + + + true + 4 + + + + + + + + + + **/*.md + + + + + + + + apply + + compile + + + + + + + + com.slack.api + slack-api-client + 1.49.0 + + + org.junit.jupiter + junit-jupiter + 6.1.0 + test + + + com.squareup.okhttp3 + mockwebserver + 4.12.0 + test + + + diff --git a/methods/src/main/java/chat/ChatPostMessage.java b/methods/src/main/java/chat/ChatPostMessage.java new file mode 100644 index 0000000..4a25283 --- /dev/null +++ b/methods/src/main/java/chat/ChatPostMessage.java @@ -0,0 +1,38 @@ +package chat; + +import com.slack.api.Slack; +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.SlackApiException; +import com.slack.api.methods.request.chat.ChatPostMessageRequest; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; +import java.io.IOException; + +/** + * Sends a message to a channel with the chat.postMessage method. + * {@link https://docs.slack.dev/reference/methods/chat.postmessage} + */ +public class ChatPostMessage { + + public static ChatPostMessageResponse example01(Slack slack) throws IOException, SlackApiException { + // Read a token from the environment variables + String token = System.getenv("SLACK_TOKEN"); + + // Initialize an API Methods client with the given token + MethodsClient methods = slack.methods(token); + + // Build a request object + ChatPostMessageRequest request = ChatPostMessageRequest.builder() + .channel("C123ABC456") + .text("Here's a message for you") + .build(); + + // Get a response as a Java object + ChatPostMessageResponse response = methods.chatPostMessage(request); + + return response; + } + + public static void main(String[] args) throws IOException, SlackApiException { + System.out.println(example01(Slack.getInstance())); + } +} diff --git a/methods/src/test/java/chat/ChatPostMessageTest.java b/methods/src/test/java/chat/ChatPostMessageTest.java new file mode 100644 index 0000000..ac9566b --- /dev/null +++ b/methods/src/test/java/chat/ChatPostMessageTest.java @@ -0,0 +1,51 @@ +package chat; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.slack.api.Slack; +import com.slack.api.SlackConfig; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ChatPostMessageTest { + + MockWebServer server; + Slack slack; + + @BeforeEach + public void setup() throws Exception { + server = new MockWebServer(); + server.start(); + SlackConfig config = new SlackConfig(); + config.setMethodsEndpointUrlPrefix(server.url("/api/").toString()); + slack = Slack.getInstance(config); + } + + @AfterEach + public void tearDown() throws Exception { + server.shutdown(); + } + + @Test + public void sends() throws Exception { + server.enqueue(new MockResponse().setBody("{\"ok\":true}")); + + ChatPostMessageResponse response = ChatPostMessage.example01(slack); + assertTrue(response.isOk()); + + RecordedRequest request = server.takeRequest(); + assertEquals("/api/chat.postMessage", request.getPath()); + + String body = URLDecoder.decode(request.getBody().readUtf8(), StandardCharsets.UTF_8); + assertTrue(body.contains("channel=C123ABC456")); + assertTrue(body.contains("text=Here's a message for you")); + } +} From f7219709c1bac888aaad8e0d04ea084c606f9c6f Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 14 Jul 2026 16:55:05 -0700 Subject: [PATCH 2/3] ci: run methods showcase in CI Add the methods example module to the CI matrix so it is spotless-checked and tested alongside block-kit. Co-Authored-By: Claude --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2167c77..c639a83 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,7 @@ jobs: matrix: showcase: - "block-kit" + - "methods" steps: - name: Checkout code uses: actions/checkout@v7 From 9d1e5f7f4cfac6622cb6b375c1fed4c217850830 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 15 Jul 2026 00:19:19 -0700 Subject: [PATCH 3/3] feat(methods): add per-family manifest; align README copy Add a manifest.json alongside the chat example source requesting only that family's scopes (chat:write), delivering per-family scoping. Move the scope out of the README bullet into the manifest and reference it from the run instructions, using the method's exact docs description. Co-Authored-By: Claude --- methods/README.md | 4 ++-- methods/src/main/java/chat/manifest.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 methods/src/main/java/chat/manifest.json diff --git a/methods/README.md b/methods/README.md index ac32962..4749cee 100644 --- a/methods/README.md +++ b/methods/README.md @@ -8,11 +8,11 @@ Read the [docs](https://docs.slack.dev/reference/methods) to explore every metho ### chat -- **[chat.postMessage](https://docs.slack.dev/reference/methods/chat.postmessage)**: Sends a message to a channel. [Implementation](./src/main/java/chat/ChatPostMessage.java). Scopes: `chat:write`. +- **[chat.postMessage](https://docs.slack.dev/reference/methods/chat.postmessage)**: Sends a message to a channel. [Implementation](./src/main/java/chat/ChatPostMessage.java). ## Running an example -Set a bot token and run an example class directly: +Each family ships a [`manifest.json`](./src/main/java/chat/manifest.json) requesting only the scopes it needs (`chat` → `chat:write`). Create an app from it, then set a bot token and run an example class directly: ```sh export SLACK_TOKEN="xoxb-your-token" diff --git a/methods/src/main/java/chat/manifest.json b/methods/src/main/java/chat/manifest.json new file mode 100644 index 0000000..ad13ee2 --- /dev/null +++ b/methods/src/main/java/chat/manifest.json @@ -0,0 +1,22 @@ +{ + "display_information": { + "name": "Slack API Methods", + "description": "Example implementations to call \"chat\" methods" + }, + "features": { + "bot_user": { + "display_name": "Slack API Methods", + "always_online": true + } + }, + "oauth_config": { + "scopes": { + "bot": ["chat:write"] + } + }, + "settings": { + "org_deploy_enabled": true, + "socket_mode_enabled": false, + "token_rotation_enabled": false + } +}