swift-slack is an unofficial library that aims to provide a Swift equivalent of the official Slack Bolt framework and SDK available for Python, TypeScript, Java, etc. Build Slack apps using the language you love.
Documentation - Full API reference, guides, and examples
Migration guide from 0.5.x to 0.6 or newer: Migrating to SlackApp
There are two normal entry points:
- Use
SlackClientfor a low-level Web API client - Use
SlackKitfor interactive Slack apps built with Socket Mode or HTTP request handling- Use
SlackBlockKitDSLtogether to build BlockKit view in declrative style DSL
- Use
Use the package directly:
dependencies: [
.package(
url: "https://github.com/ainame/swift-slack.git",
from: "0.6.0"
)
]For smaller builds, enable only the traits your app needs:
.package(
url: "https://github.com/ainame/swift-slack.git",
from: "0.6.0",
traits: [
"SocketMode", // WebSocket support
"Events", // Events API
"WebAPI_Apps", // apps.connections.open for Socket Mode
"WebAPI_Chat", // chat.postMessage, etc.
"WebAPI_Views", // views.open, etc.
]
)SlackClient is the lower-level client surface. You provide the transport and call Web API methods directly.
Add SlackClient and OpenAPIAsyncHTTPClient as transport layer to your app target.
You can choose other transport layer available for swift-openapi-generator ecosystem.
.executableTarget(
name: "YOUR_SWIFT_APP",
dependencies: [
.product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client"),
.product(name: "SlackClient", package: "swift-slack"),
],
)import OpenAPIAsyncHTTPClient
import SlackClient
let slack = Slack(
transport: AsyncHTTPClientTransport(),
configuration: .init(token: token)
)
try await slack.client.chatPostMessage(
body: .json(.init(
channel: "#general",
text: "Hello from swift-slack"
))
)SlackKit is the umbrella product that re-exports the runtime layer and the common app-authoring types used by interactive apps.
.executableTarget(
name: "YOUR_SWIFT_APP",
dependencies: [
.product(name: "SlackKit", package: "swift-slack"),
],
)import SlackKit
let router = Router()
router.onEvent(AppMentionEvent.self) { context, _, event in
try await context.client.chatPostMessage(
body: .json(.init(
channel: event.channel,
text: "Hello!"
))
)
}
router.onSlashCommand("/echo") { context, payload in
try await context.ack()
try await context.say(channel: payload.channelId, text: "Echo: \(payload.text)")
}
let app = SlackApp(
configuration: .init(
appToken: appToken,
token: token
),
router: router,
mode: .socketMode()
)
try await app.run()If you need setup work before the runtime starts, use the preparing hook:
try await app.run { slack in
_ = try await slack.authTest()
}For signed Slack requests over HTTP, use the runtime with an adapter such as HummingbirdAdapter:
import SlackKit
let router = Router()
let adapter = HummingbirdAdapter(hostname: "0.0.0.0", port: 8080)
let app = SlackApp(
configuration: .init(
token: token,
signingSecret: signingSecret
),
router: router,
mode: .http(adapter)
)
try await app.run()Two ways to build Slack Block Kit messages:
import SlackBlockKit
let block = SectionBlock(
text: TextObject(text: "Hello *world*!", type: .mrkdwn),
accessory: ButtonElement(
text: TextObject(text: "Click me", type: .plainText),
actionId: "button_click"
)
)import SlackBlockKitDSL
let block = Section {
Text("Hello *world*!").style(.mrkdwn)
}
.accessory(
Button("Click me").actionId("button_click")
)
// Or define reusable views
struct WelcomeModal: SlackModalView {
var title: Text { "Welcome" }
var blocks: [Block] {
Header { Text("Getting Started") }
Section { Text("Welcome to our app!") }
}
}See Examples for more patterns.
SlackApp follows Bolt-style acknowledgment semantics:
- Events API handlers are auto-acked and receive
EventContext - Slash commands, block actions, shortcuts, and view handlers receive
Contextand must callack() - Router registrations are overwrite-based, so the last handler for the same key wins
onSlackMessageMatched(...)was removed; userouter.onEvent(MessageEvent.self)and filter in the handler
router.onViewSubmission("form") { context, payload in
guard let email = payload.view.state?["email_block", "email_input"]?.value else {
try await context.ack(errors: ["email_block": "Please enter an email"])
return
}
try await context.ack()
}SlackApp conforms to Service, so it can run inside swift-service-lifecycle:
import Logging
import ServiceLifecycle
import SlackKit
let group = ServiceGroup(
services: [app],
gracefulShutdownSignals: [.sigterm, .sigint],
logger: Logger(label: "MySlackApp")
)
try await group.run()Request Format: The library automatically converts JSON requests to form-encoded format that Slack expects. This is transparent to users but may change in future versions of swift-openapi-generator.
Generated from official Slack API sources:
- Web API: slack-ruby/slack-api-ref for request parameters
- Responses/Events: slackapi/java-slack-sdk for response schemas
Uses quicktype to generate JSON schemas, then swift-openapi-generator for Swift code. Many properties are optional due to schema inference limitations.
This package includes generated Web API and Events/Models layers derived from the upstream reference data above. Top-level attribution and bundled upstream MIT license texts are available in THIRD_PARTY_NOTICES.md.
Requirements: Swift 6.2+, SwiftFormat, Node.js
git clone --recursive https://github.com/ainame/swift-slack.git
make update && make generateNote: This is an unofficial, community-based project not affiliated with Slack Technologies, LLC.