Building a Real-Time Messaging Service with Nitric SDK in Go
Tags: go, tutorial, cloudcomputing, websockets
Published: 2023-10-05 19:59:48

In this tutorial, we will build a simple real-time messaging service using the Nitric SDK in Go. 

Our application will allow multiple clients to connect via WebSockets and broadcast messages to all connected clients.

> If you haven't used the [Nitric SDK](https://nitric.io) before, then start with this [tutorial] (https://dev.to/rsiv/your-first-api-with-go-nitric-39b7) to get your project scaffolded and ready to run.

### Pre-Requisites:

- Go installed on your machine.
- Nitric SDK for Go.

### Step 1: Import Necessary Libraries
Firstly, we need to import the required libraries.

```go
import (
  "fmt"
  "github.com/nitrictech/go-sdk/faas"
  "github.com/nitrictech/go-sdk/nitric"
)
```

### Step 2: Initialize Nitric Application
Inside the `main` function, initialize a new WebSocket and a new collection to store connection information.

```go
func main() {
  ws, err := nitric.NewWebsocket("public")
  if err != nil {
    return
  }

  connections, err := nitric.NewCollection("connections").With(nitric.CollectionEverything...)
  if err != nil {
    return
  }

  // TODO: onConnect, onDisconnect, onMessage handlers

  if err := nitric.Run(); err != nil {
    fmt.Println(err)
  }
}
```

### Step 3: Handle WebSocket Events
We'll define three event handlers: one for new connections, one for disconnections, and one for incoming messages.

#### a) Connection Event:
Register a new connection by saving the connection ID to the "connections" collection.

```go
ws.On(faas.WebsocketConnect, func(ctx *faas.WebsocketContext, next faas.WebsocketHandler) (*faas.WebsocketContext, error) {
  err := connections.Doc(ctx.Request.ConnectionID()).Set(ctx.Request.Context(), map[string]interface{}{
    "connectionId": ctx.Request.ConnectionID(),
  })
  if err != nil {
    return ctx, err
  }

  return next(ctx)
})
```

#### b) Disconnection Event:
Remove a registered connection from the "connections" collection on disconnection.

```go
ws.On(faas.WebsocketDisconnect, func(ctx *faas.WebsocketContext, next faas.WebsocketHandler) (*faas.WebsocketContext, error) {
  err := connections.Doc(ctx.Request.ConnectionID()).Delete(ctx.Request.Context())
  if err != nil {
    return ctx, err
  }

  return next(ctx)
})
```

#### c) Message Event:
Broadcast incoming messages to all the registered WebSocket connections.

```go
ws.On(faas.WebsocketMessage, func(ctx *faas.WebsocketContext, next faas.WebsocketHandler) (*faas.WebsocketContext, error) {
  connectionStream, err := connections.Query().Stream(ctx.Request.Context())
  if err != nil {
    return ctx, err
  }

  for {
    res, err := connectionStream.Next()
    if err != nil {
      break // reached the end of the documents
    }

    connectionId, ok := res.Content()["connectionId"].(string)
    if !ok {
      continue
    }

    err = ws.Send(ctx.Request.Context(), connectionId, ctx.Request.Data())
    if err != nil {
      return ctx, err
    }
  }

  return next(ctx)
})
```

Now, you have a basic real-time messaging service set up. Clients can connect to your service via WebSocket, send messages, and those messages will be broadcasted to all connected clients in real-time.

You can test it out by using the [Nitric CLI](https://nitric.io/docs/guides/getting-started).