The Go SDK for Ably Pub/Sub: publish and subscribe to channels, and use message history and presence, from servers and from applications on end-user devices.
The SDK has two entry points, one for each side of the connection. You choose the entry point by where your code runs, and create your client with its constructor.
| Package | Use it for | Entry point |
|---|---|---|
github.com/ably/ably-pubsub-go/v2/server/pubsub |
Servers and other trusted backend environments | NewHTTPClient, NewRealtimeClient |
github.com/ably/ably-pubsub-go/v2/device/pubsub |
Applications on end-user devices | NewClient |
Go 1.18 or later.
Use exactly one of server/pubsub or device/pubsub in a program.
go get github.com/ably/ably-pubsub-go/v2/server/pubsubgo get github.com/ably/ably-pubsub-go/v2/device/pubsubUse an API key on a server. The samples read it from the ABLY_API_KEY environment variable; set it
to an API key from your Ably dashboard. The
following code connects, subscribes to a channel, publishes a message to it and waits for the
message to arrive.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/ably/ably-pubsub-go/v2/server/pubsub"
)
func main() {
ctx := context.Background()
ablyAPIKey := os.Getenv("ABLY_API_KEY")
client, err := pubsub.NewRealtimeClient(pubsub.WithKey(ablyAPIKey))
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Subscribing attaches the channel. Publishing while the client is still
// connecting queues the message until it's connected.
channel := client.Channels.Get("test-channel")
received := make(chan *pubsub.Message, 1)
unsubscribe, err := channel.SubscribeAll(ctx, func(msg *pubsub.Message) {
select {
case received <- msg:
default:
}
})
if err != nil {
log.Fatal(err)
}
defer unsubscribe()
if err := channel.Publish(ctx, "test-event", "hello world"); err != nil {
log.Fatal(err)
}
msg := <-received
fmt.Printf("Received: %v\n", msg.Data)
}To publish over HTTP without a realtime connection, create an HTTP client instead:
package main
import (
"context"
"log"
"os"
"github.com/ably/ably-pubsub-go/v2/server/pubsub"
)
func main() {
ablyAPIKey := os.Getenv("ABLY_API_KEY")
client, err := pubsub.NewHTTPClient(pubsub.WithKey(ablyAPIKey))
if err != nil {
log.Fatal(err)
}
err = client.Channels.Get("test-channel").Publish(context.Background(), "test-event", "hello world")
if err != nil {
log.Fatal(err)
}
}Important
Server clients must authenticate with an API key. To use a token instead, see Server clients and token authentication.
The following endpoint issues token requests. Devices set WithAuthURL to its URL, for example
https://your-server.example.com/ably-auth:
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"github.com/ably/ably-pubsub-go/v2/server/pubsub"
)
func main() {
ablyAPIKey := os.Getenv("ABLY_API_KEY")
client, err := pubsub.NewHTTPClient(pubsub.WithKey(ablyAPIKey))
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/ably-auth", func(w http.ResponseWriter, r *http.Request) {
// Authenticate the caller first. Grant only the operations this user needs.
userID := "me" // the signed-in user's ID, from your session
tokenRequest, err := client.Auth.CreateTokenRequest(&pubsub.TokenParams{
ClientID: userID,
// Without a capability, the token gets all of the API key's capabilities.
Capability: `{"test-channel":["publish","subscribe","history"]}`,
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(tokenRequest)
})
log.Fatal(http.ListenAndServe(":8080", nil))
}See token authentication for how devices use it.
Authenticate a device with tokens issued by your own server, such as the endpoint above, through
WithAuthURL or WithAuthCallback. Never embed an API key in an application that runs on an
end-user device.
package main
import (
"context"
"fmt"
"log"
"github.com/ably/ably-pubsub-go/v2/device/pubsub"
)
func main() {
ctx := context.Background()
client, err := pubsub.NewClient(
pubsub.WithAuthURL("https://your-server.example.com/ably-auth"),
pubsub.WithClientID("me"),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// The client connects automatically. Subscribing attaches the channel.
channel := client.Channels.Get("test-channel")
received := make(chan *pubsub.Message, 1)
unsubscribe, err := channel.SubscribeAll(ctx, func(msg *pubsub.Message) {
select {
case received <- msg:
default:
}
})
if err != nil {
log.Fatal(err)
}
defer unsubscribe()
if err := channel.Publish(ctx, "test-event", "hello world"); err != nil {
log.Fatal(err)
}
msg := <-received
fmt.Printf("Received: %v\n", msg.Data)
}To get tokens from your own code instead of a URL, use WithAuthCallback. It returns a token, a
token request or token details (pubsub.Tokener):
client, err := pubsub.NewClient(
pubsub.WithAuthCallback(func(ctx context.Context, params pubsub.TokenParams) (pubsub.Tokener, error) {
return requestTokenFromYourServer(ctx, params) // your function
}),
pubsub.WithClientID("me"),
)Version 2.0 moves to a new module path and replaces the ably package with server and device
entry points.
| 1.x | 2.0 | |
|---|---|---|
| Module | github.com/ably/ably-go |
github.com/ably/ably-pubsub-go/v2 |
| Import | github.com/ably/ably-go/ably |
github.com/ably/ably-pubsub-go/v2/server/pubsub or github.com/ably/ably-pubsub-go/v2/device/pubsub |
| Realtime client | ably.NewRealtime(...) |
pubsub.NewRealtimeClient(...) (server) or pubsub.NewClient(...) (device) |
| HTTP client | ably.NewREST(...) |
pubsub.NewHTTPClient(...) (server only) |
See UPDATING.md for all other changes.
Both packages export the same With... options. Pass them to the constructors.
WithEndpoint selects the Ably host for both HTTP requests and the realtime connection. It
replaces the 1.x WithEnvironment, WithRESTHost and WithRealtimeHost options.
ablyAPIKey := os.Getenv("ABLY_API_KEY")
client, err := pubsub.NewRealtimeClient(
pubsub.WithKey(ablyAPIKey),
pubsub.WithEndpoint("nonprod:sandbox"),
)Never put a port in the endpoint: localhost:8080 is not a hostname and does not resolve. Set the
port with WithTLSPort instead, or with WithPort when TLS is off (WithTLS(false), which needs
token authentication). See
Host options are replaced by WithEndpoint
for how each value resolves.
The SDK uses Go's standard proxy settings. Set the HTTP_PROXY and HTTPS_PROXY environment
variables, including the scheme, and both HTTP requests and the realtime connection go through the
proxy:
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080If the proxy needs authentication, put the credentials in the URL, for example
http://username:password@proxy.example.com:8080. See
http.ProxyFromEnvironment for the details.
To set a proxy in code, pass your own http.Client with WithHTTPClient. It applies to HTTP
requests only; the realtime connection still uses the environment variables.
proxyURL, err := url.Parse("http://proxy.example.com:8080")
if err != nil {
log.Fatal(err)
}
ablyAPIKey := os.Getenv("ABLY_API_KEY")
client, err := pubsub.NewHTTPClient(
pubsub.WithKey(ablyAPIKey),
pubsub.WithHTTPClient(&http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
}),
)Connection reliability then depends on the proxy, and Ably can't help with errors the proxy introduces.
Set the level with WithLogLevel: LogNone, LogError, LogWarning, LogInfo, LogVerbose
or LogDebug (the most verbose). The default is LogWarning. Logs go to standard error unless
you pass your own Logger with WithLogHandler:
type myLogger struct{}
func (myLogger) Printf(level pubsub.LogLevel, format string, v ...interface{}) {
log.Printf(format, v...)
}
ablyAPIKey := os.Getenv("ABLY_API_KEY")
client, err := pubsub.NewRealtimeClient(
pubsub.WithKey(ablyAPIKey),
pubsub.WithLogLevel(pubsub.LogDebug),
pubsub.WithLogHandler(myLogger{}),
)- Push notification targets don't apply to this SDK.
- The Push Notifications Admin API isn't supported (REST, realtime).
- Channel SUSPENDED state is only partly supported.
- Ping isn't implemented.
- Getting started with Pub/Sub using Go
- Ably Pub/Sub documentation and examples
- UPDATING.md: migrating from 1.x
- CHANGELOG.md: release notes; all Ably releases are listed on changelog.ably.com
- examples/: example programs
Read CONTRIBUTING.md before contributing.
For help, visit Ably's support page. Report bugs and compatibility problems on GitHub Issues.
Licensed under the Apache License, Version 2.0. See LICENSE.
