A Slack notification channel for Goravel's
notification module,
using the Slack Web API (chat.postMessage + a bot token) instead of
Incoming Webhooks — so RouteNotificationFor("slack") can return a
channel name like #general or a user ID for a DM, rather than being
locked to whichever single channel an Incoming Webhook was created for.
Not yet tagged
Run the command below in your project to install the package automatically:
./artisan package:install github.com/goravel/slackOr check the setup file to install the package manually.
./artisan package:install github.com/goravel/slack generates
config/slack.go in your app automatically — no separate publish step
needed. Set your bot token in .env:
SLACK_BOT_TOKEN=xoxb-your-token-here
Create a bot at api.slack.com/apps with
the chat:write scope, then invite it to any channel it needs to post
in — a bot can only post to channels it's been added to.
The generated config (import path varies per app — this is what
goravel/goravel's default skeleton generates; your app's own
app/facades package, not github.com/goravel/framework/facades
directly, since the template substitutes whatever your app's own
facades package path actually is):
package config
import (
"goravel/app/facades"
)
func init() {
config := facades.Config()
config.Add("slack", map[string]any{
"token": config.Env("SLACK_BOT_TOKEN", ""),
})
}Implement contracts.Notification on any notification and add
"slack" to its Via() list:
package notifications
import (
"github.com/goravel/framework/contracts/notification"
"github.com/goravel/slack/contracts"
)
type InvoicePaid struct {
Invoice *models.Invoice
}
func (n *InvoicePaid) Via(notifiable notification.Notifiable) []string {
return []string{contracts.ChannelName}
}
func (n *InvoicePaid) ToSlack(notifiable notification.Notifiable) contracts.Message {
return contracts.Message{
Text: "Invoice #" + n.Invoice.Number + " was paid.",
Attachments: []contracts.Attachment{
{
Color: "good",
Fields: []contracts.Field{
{Title: "Amount", Value: n.Invoice.Amount, Short: true},
{Title: "Customer", Value: n.Invoice.CustomerName, Short: true},
},
},
},
}
}Route to a channel or user by implementing contracts.Routable on your
notifiable model — preferred over the generic RouteNotificationFor,
since a typo'd channel name string can't silently drop the route:
func (u *User) RouteNotificationForSlack(notification notification.Notification) string {
return "#billing" // or a user ID for a DM, e.g. "U0123ABC456"
}An empty result from RouteNotificationForSlack isn't itself an error
— it falls back to the generic RouteNotificationFor, using
contracts.ChannelName instead of a raw "slack" string so a typo is
a compile error, not a silently dropped notification:
func (u *User) RouteNotificationFor(channel string) any {
if channel == contracts.ChannelName {
return "#billing"
}
return nil
}A notification that doesn't implement contracts.Notification still
gets a minimal default message (its Go type name) if "slack" is in
Via() — useful for quick alerts without writing a ToSlack method.
import "github.com/goravel/slack/contracts"
facades.Notification().
Route(contracts.ChannelName, "#alerts").
Notify(&DeploymentFinished{})slack.NewChannel takes slack-go/slack's own variadic Options — use
OptionAPIURL to point requests at an httptest.Server instead of
hitting the real Slack API:
mux := http.NewServeMux()
mux.HandleFunc("/chat.postMessage", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"ok": true}`))
})
server := httptest.NewServer(mux)
defer server.Close()
ch := slack.NewChannel("xoxb-test", slackgo.OptionAPIURL(server.URL+"/"))Need a custom *http.Client instead (a shared connection pool, a proxy,
request logging)? Pass slackgo.OptionHTTPClient(yourClient) the same
way — there's no separate parameter for it, just another Option.
It's the de facto standard, actively maintained Go Slack SDK, and it
already handles Slack's biggest testing gotcha for you: Slack's Web API
returns HTTP 200 even when a request fails — the real success/failure
signal is the "ok" boolean in the JSON response body, not the status
code. slack-go/slack's PostMessage surfaces that as a normal Go
error automatically, so this package doesn't do any manual status-code
or response-body parsing itself.
Slack's older Incoming Webhooks mechanism binds one webhook URL to one
fixed channel, decided when the webhook is created — there's no way to
pick a different channel per notification. The Web API's chat.postMessage
takes the target channel as a request parameter instead, so a single bot
token can post anywhere it's been invited, and RouteNotificationFor
can vary per notifiable the same way the mail and database channels do.
The Goravel Slack package is open-sourced software licensed under the MIT license.