Slack SDK for Java

repository·main·Indexed 20 days ago

https://github.com/slackapi/java-slack-sdk

Idiomatic tools for interacting with the Slack platform on the JVM. The SDK provides two primary paths: the Bolt framework for building interactive apps (supporting HTTP servers, Socket Mode, Spring Boot 2/3, and Quarkus) and a low-level Slack API client for direct service integration. Compatible with Java, Kotlin, Groovy, and Scala.

Tokens
106.9K
Snippets
232
Records
301
Agent score
70%

What's inside java-slack-sdk

  1. Choose between Bolt for Java and the Slack API Client

    main

    The Java Slack SDK provides two primary ways to build Slack applications depending on your needs:

    • Bolt for Java: A framework designed for building modern Slack apps easily using a simplified API. Use this if you want a high-level, streamlined development experience.
    • Slack API Client: A low-level client that provides direct access to the Slack Web API. Use this if you require maximum flexibility or want to integrate only the core API capabilities into your existing application.
  2. Choose between Bolt for Java and the Java Slack SDK

    main

    The Java Slack SDK provides two distinct ways to build Slack apps depending on your needs:

    1. Bolt for Java: A framework that provides a simplified, high-level API. Use this if you want a streamlined experience for writing Slack apps.
    2. Java Slack SDK (Web API Client): A lower-level approach using the Slack API client directly. Use this when you need a highly customized implementation or direct control over the Slack Web API calls.

    Both modules are compatible with any JVM language, including Kotlin, Groovy, and Scala.

  3. Understand SCIM API rate limits and AsyncSCIMClient

    main

    SCIM API rate limits apply to all SCIM apps within an organization, rather than on a per-app basis.

    Synchronous vs. Asynchronous Clients

    • SCIMClient (Synchronous): Sends requests immediately and does not manage burst traffic.
    • AsyncSCIMClient (Asynchronous): Designed with rate limits in mind. It uses internal queuing to avoid burst traffic and can delay requests to prevent hitting rate limits.

    Metrics and Rate Limit Estimation

    Both sync and async clients share a MetricsDatastore to track traffic generated toward the Slack platform. This allows the AsyncSCIMClient to estimate remaining capacity and adjust request timing. By default, this datastore is an in-memory implementation using the JVM heap.

    To use the asynchronous client, use slack.scimAsync(token) which returns CompletableFuture objects for API calls.

    import com.slack.api.Slack;
    import com.slack.api.scim.response.*;
    import java.util.concurrent.CompletableFuture;
    
    Slack slack = Slack.getInstance();
    String token = "xoxp-***"; // Org admin user token
    
    CompletableFuture<UsersSearchResponse> users = slack.scimAsync(token).searchUsers(req -> req
      .startIndex(1)
      .count(100)
      .filter("userName Eq \"Carly\"")
    );
  4. How the Bolt OAuth flow works

    main

    To handle the OAuth flow for distributing your app, a Bolt application must implement the following logic:

    1. OAuth Flow Initiation Endpoint:

      • Redirects the user to the Slack Authorize endpoint.
      • Generates a state parameter value for later validation.
      • Appends client_id, scope, user_scope (for v2 only), and state to the URL.
    2. Redirect Handling Endpoint:

      • Processes the request redirected from Slack.
      • Validates that the state parameter is legitimate.
      • Calls the oauth.v2.access API method (or oauth.access for legacy apps) to issue and save the access token, completing the installation.
    3. Completion/Error Pages:

      • Provides pages to guide the user after a successful or failed installation. These can be hosted by the Bolt app or external services.
  5. How Bolt handles Events API requests

    main

    When using the Bolt framework, the library automates several critical steps required to handle Slack events securely and correctly:

    1. Request Verification: Validates the request from Slack (e.g., checking X-Slack-Signature and X-Slack-Request-Timestamp).
    2. Payload Parsing: Parses the JSON request body and identifies the type of the event.
    3. Event Dispatching: Matches the event type to your defined listeners.
    4. Acknowledgment: Automatically handles the requirement to respond with a 200 OK to Slack.

    Critical Requirement: Your application must acknowledge the event using the ack() method within 3 seconds. If you fail to respond within this window, Slack will retry the request after a delay.

  6. Manage Assistant thread state and context

    main

    When handling events within an Assistant thread, you can manipulate the user experience using the context object (ctx):

    • Set Status: Use ctx.setStatus(String status) or ctx.setStatus(String status, List<String> steps) to show the user what the AI is doing (e.g., "is typing..." or "analyzing files...").
    • Access Thread Context: Use ctx.getThreadContext() to retrieve metadata about the current conversation, such as the getChannelId(), which allows the assistant to be aware of the surrounding channel context.
    • Suggested Prompts: In the threadStarted handler, use ctx.setSuggestedPrompts(...) to provide clickable buttons that help the user start a conversation.
  7. Switch between V2 and Classic OAuth flows

    main

    Slack supports two OAuth flows:

    1. V2 OAuth 2.0 Flow (Default): Enables granular permissions. Uses https://slack.com/oauth/v2/authorize and the oauth.v2.access method.
    2. Classic OAuth Flow: The older method. Uses https://slack.com/oauth/authorize and the oauth.access method.

    To enable the Classic flow, use AppConfig.setClassicAppPermissionsEnabled(true). The InstallationService automatically handles the differences in response structures between the two flows.

    AppConfig appConfig = new AppConfig();
    appConfig.setClassicAppPermissionsEnabled(true);
    App app = new App(appConfig);
  8. Switch between Granular Permission (V2) and Classic OAuth flows

    main

    Slack supports two OAuth flows. By default, Bolt uses the V2 (Granular Permission) flow, which allows for more precise permission requests.

    FeatureV2 OAuth 2.0 (Default)Classic OAuth
    Authorization URLhttps://slack.com/oauth/v2/authorizehttps://slack.com/oauth/authorize
    Token APIoauth.v2.accessoauth.access

    To switch to the Classic OAuth flow, you must configure the AppConfig with classicAppPermissionsEnabled(true). The InstallationService automatically handles the differences in response structures between the two flows.

    AppConfig appConfig = new AppConfig();
    appConfig.setClassicAppPermissionsEnabled(true);
    App app = new App(appConfig);
  9. Handle Events API requests in Bolt

    main

    When building an app with Bolt, the framework automates several manual steps required by the Events API.

    Manual steps Bolt handles for you:

    • Request Verification: Verifying that requests actually come from Slack.
    • Payload Parsing: Parsing the JSON request body and identifying the event.type.
    • Acknowledgment: Automatically responding to Slack with a 200 OK when you call ctx.ack().

    Key Requirements:

    • Acknowledgment Timing: You must respond to the Slack API server within 3 seconds by calling the ack() method. Failure to do so may cause Slack to retry the request.
    • Replying to Events: Event payloads do not include a response_url. You cannot use ctx.ack() to post a message. To reply to a user in the same conversation where an event occurred, use the chat.postMessage method with the channel ID provided in the event payload.
  10. Modal development best practices and tips

    main

    When developing modals, keep these technical requirements and patterns in mind:

    • Opening Modals: You must include a trigger_id from a user interaction payload to open a modal view.
    • Data Extraction: Only inputs defined with "type": "input" blocks are accessible in the view.state.values field during a view_submission.
    • Identifying Components:
      • Use callback_id to identify the modal itself.
      • Use a combination of block_id and action_id to identify specific inputs within view.state.values.
    • State Management: Use the view.private_metadata property to store internal state or results from block_actions within the modal.
    • Interaction vs. Submission:
      • Use views.update or views.push for block_actions (interactive components).
      • Use response_action (e.g., errors, update, push, clear) within the acknowledgment for view_submission requests.
  11. Handle Block Kit Interactions with Bolt

    main

    When a user interacts with a Block Kit element (e.g., clicking a button), Slack sends a request to your app. Bolt simplifies the handling of these interactions.

    Key Requirements for Bolt Apps:

    1. Acknowledge quickly: You must respond to Slack within 3 seconds using the ack() method. If you fail to respond within this window, the user will see a timeout notification.
    2. Handle action_id: Your code must specify the action_id (as a string or regex) to listen for specific interactions.
    3. Respond to users:
      • For immediate feedback or asynchronous replies, use ctx.respond(). This uses the response_url provided in the payload, which is valid for 30 minutes and can be used up to 5 times.
      • For specific interactive elements like external_select, you must include the correct response format within the ack() argument.
  12. Carry data to a modal using private_metadata

    main

    The private_metadata field allows you to pass information to a modal. It is a single string with a maximum of 3000 characters. If you need to pass multiple values, serialize them (e.g., into a JSON string) before setting the field. You can retrieve this metadata in subsequent interaction requests (like block_actions or view_submission) via the view.getPrivateMetadata() method.

    import com.slack.api.bolt.util.JsonOps;
    
    class PrivateMetadata {
      String responseUrl;
      String commandArgument;
    }
    
    app.command("/meeting", (req, ctx) -> {
      PrivateMetadata data = new PrivateMetadata();
      data.responseUrl = ctx.getResponseUrl();
      data.commandArgument = req.getPayload().getText();
    
      return view(view -> view.callbackId("meeting-arrangement")
        .type("modal")
        .notifyOnClose(true)
        .privateMetadata(JsonOps.toJsonString(data))
        // omitted ...