This repository was archived by the owner on May 20, 2025. It is now read-only.
  
  
  - 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 17
 
add go guide for real time chat and a guide to use terratest with the same project #639
          
     Merged
      
      
    
  
     Merged
                    Changes from 1 commit
      Commits
    
    
            Show all changes
          
          
            15 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      ceaf0b8
              
                add guides.
              
              
                raksiv ad17e15
              
                update dictionary
              
              
                raksiv 4a19ca7
              
                add frontmatter
              
              
                davemooreuws 36a99f0
              
                fix spellcheck
              
              
                davemooreuws 258e5c5
              
                clean up
              
              
                davemooreuws f1c6f1c
              
                Update docs/guides/go/realtime-messaging.mdx
              
              
                davemooreuws 6be0994
              
                Update docs/guides/go/realtime-messaging.mdx
              
              
                davemooreuws fc19248
              
                Update docs/guides/go/realtime-messaging.mdx
              
              
                davemooreuws d5bd34e
              
                Apply suggestions from code review
              
              
                davemooreuws 04eaddd
              
                review suggestions
              
              
                HomelessDinosaur 4a91917
              
                fix link for install
              
              
                HomelessDinosaur e0be643
              
                missing backtick
              
              
                davemooreuws 63addf1
              
                Apply suggestions from code review
              
              
                raksiv 4bd4355
              
                Apply suggestions from code review
              
              
                jyecusch d78be52
              
                add link to source
              
              
                davemooreuws File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,309 @@ | ||
| export const description = | ||
| 'Use the Nitric framework to easily build and deploy Go WebSocket applications for AWS, Azure or GCP' | ||
| 
     | 
||
| export const title_meta = | ||
| 'Building your first WebSocket Application with Go and Nitric' | ||
                
      
                  HomelessDinosaur marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| # Building your first WebSocket Application with Nitric | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ## What we'll be doing | ||
| 
     | 
||
| 1. Use Nitric to create a WebSocket endpoint | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 2. Manage WebSocket connections using a Key-Value store | ||
| 3. Handle WebSocket events: | ||
| - Register connections on connect | ||
| - Remove connections on disconnect | ||
| - Broadcast messages to all connected clients | ||
| 4. Run locally for testing | ||
| 5. Deploy to a cloud of your choice | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ## Prerequisites | ||
| 
     | 
||
| - [Go](https://go.dev/dl/) | ||
| - The [Nitric CLI](https://nitric.io/docs/installation) | ||
| - An [AWS](https://aws.amazon.com), [GCP](https://cloud.google.com), or [Azure](https://azure.microsoft.com) account (_your choice_) | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ## Getting started | ||
| 
     | 
||
| We'll start by creating a new project for our WebSocket application. | ||
| 
     | 
||
| ```bash | ||
| nitric new my-websocket-app go-starter | ||
| ``` | ||
| 
     | 
||
| Next, open the project in your editor of choice. | ||
| 
     | 
||
| ```bash | ||
| cd my-websocket-app | ||
| ``` | ||
| 
     | 
||
| Make sure all dependencies are resolved: | ||
| 
     | 
||
| ```bash | ||
| go mod tidy | ||
| ``` | ||
| 
     | 
||
| The scaffolded project should have the following structure: | ||
| 
     | 
||
| ```text | ||
| +--services/ | ||
| | +-- hello/ | ||
| | +-- main.go | ||
| | ... | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| +--nitric.yaml | ||
| +--go.mod | ||
| +--go.sum | ||
| +--golang.dockerfile | ||
| +--.gitignore | ||
| +--README.md | ||
| ``` | ||
| 
     | 
||
| You can test the project to verify everything is working as expected: | ||
| 
     | 
||
| ```bash | ||
| nitric start | ||
| ``` | ||
| 
     | 
||
| If everything is working as expected, you can now delete all files/folders in the `services/` folder. We'll create new services in this guide. | ||
| 
     | 
||
| ## Building the WebSocket Application | ||
| 
     | 
||
| Let's begin by setting up the WebSocket application. First, create a new folder called `websockets` within the services directory. Inside this folder, add a file named `main.go`, and include the following code: | ||
| 
     | 
||
| ```go | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| package main | ||
| 
     | 
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| 
     | 
||
| "github.com/nitrictech/go-sdk/nitric" | ||
| "github.com/nitrictech/go-sdk/nitric/keyvalue" | ||
| "github.com/nitrictech/go-sdk/nitric/websockets" | ||
| ) | ||
| 
     | 
||
| func main() { | ||
| // Create a WebSocket endpoint named "public". | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| ws := nitric.NewWebsocket("public") | ||
| 
     | 
||
| // Initialize a KV store named "connections" with Get, Set, and Delete permissions. | ||
| connections := nitric.NewKv("connections").Allow(keyvalue.KvStoreGet, keyvalue.KvStoreSet, keyvalue.KvStoreDelete) | ||
| 
     | 
||
| // Handle new WebSocket connections by storing the connection ID in the KV store. | ||
| ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) { | ||
| err := connections.Set(context.TODO(), ctx.Request.ConnectionID(), map[string]interface{}{ | ||
| "connectionId": ctx.Request.ConnectionID(), | ||
| }) | ||
| if err != nil { | ||
| return | ||
| } | ||
| }) | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| // Add event handlers here | ||
| 
     | 
||
| nitric.Run() | ||
| } | ||
| ``` | ||
| 
     | 
||
| Here we're creating: | ||
| 
     | 
||
| - A WebSocket endpoint named `public` | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| - A Key-Value store named `connections` to track WebSocket connections | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| From here, let's add some features to that function that allow us to manage connections and broadcast messages. | ||
| 
     | 
||
| <Note> | ||
| You could separate some or all of these event handlers into their own services | ||
| if you prefer. For simplicity, we'll group them together in this guide. | ||
| </Note> | ||
| 
     | 
||
| ### Register connections on connect | ||
| 
     | 
||
| ```go | ||
| ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) { | ||
| err := connections.Set(context.TODO(), ctx.Request.ConnectionID(), map[string]interface{}{ | ||
| "connectionId": ctx.Request.ConnectionID(), | ||
| }) | ||
| if err != nil { | ||
| return | ||
                
      
                  jyecusch marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
                
      
                  raksiv marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| }) | ||
| ``` | ||
| 
     | 
||
| ### Remove connections on disconnect | ||
| 
     | 
||
| ```go | ||
| ws.On(websockets.EventType_Disconnect, func(ctx *websockets.Ctx) { | ||
| err := connections.Delete(context.TODO(), ctx.Request.ConnectionID()) | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| if err != nil { | ||
| return | ||
| } | ||
                
      
                  raksiv marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| }) | ||
| ``` | ||
| 
     | 
||
| ### Broadcast messages to all connected clients | ||
| 
     | 
||
| ```go | ||
| ws.On(websockets.EventType_Message, func(ctx *websockets.Ctx) { | ||
| connectionStream, err := connections.Keys(context.TODO()) | ||
| if err != nil { | ||
| return | ||
| } | ||
                
      
                  raksiv marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| senderId := ctx.Request.ConnectionID() | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| for { | ||
| connectionId, err := connectionStream.Recv() | ||
| if err != nil { | ||
| break | ||
| } | ||
                
      
                  raksiv marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| if connectionId == senderId { | ||
| continue | ||
| } | ||
| 
     | 
||
| message := fmt.Sprintf("%s: %s", senderId, ctx.Request.Message()) | ||
| err = ws.Send(context.TODO(), connectionId, []byte(message)) | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| if err != nil { | ||
| return | ||
| } | ||
                
      
                  raksiv marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| }) | ||
| ``` | ||
| 
     | 
||
| ### Bringing it all together | ||
| 
     | 
||
| <details> | ||
| <summary>Your code should look like this:</summary> | ||
| 
     | 
||
| ```go | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| package main | ||
| 
     | 
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| 
     | 
||
| "github.com/nitrictech/go-sdk/nitric" | ||
| "github.com/nitrictech/go-sdk/nitric/keyvalue" | ||
| "github.com/nitrictech/go-sdk/nitric/websockets" | ||
| ) | ||
| 
     | 
||
| func main() { | ||
| // Create a WebSocket endpoint named "public". | ||
| ws := nitric.NewWebsocket("public") | ||
| 
     | 
||
| // Initialize a KV store named "connections" with Get, Set, and Delete permissions. | ||
| connections := nitric.NewKv("connections").Allow(keyvalue.KvStoreGet, keyvalue.KvStoreSet, keyvalue.KvStoreDelete) | ||
| 
     | 
||
| // Handle new WebSocket connections by storing the connection ID in the KV store. | ||
| ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) { | ||
| err := connections.Set(context.TODO(), ctx.Request.ConnectionID(), map[string]interface{}{ | ||
| "connectionId": ctx.Request.ConnectionID(), | ||
| }) | ||
| if err != nil { | ||
| return | ||
| } | ||
| }) | ||
| 
     | 
||
| ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) { | ||
| err := connections.Set(context.TODO(), ctx.Request.ConnectionID(), map[string]interface{}{ | ||
| "connectionId": ctx.Request.ConnectionID(), | ||
| }) | ||
| if err != nil { | ||
| return | ||
                
      
                  jyecusch marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| }) | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ws.On(websockets.EventType_Disconnect, func(ctx *websockets.Ctx) { | ||
| err := connections.Delete(context.TODO(), ctx.Request.ConnectionID()) | ||
| if err != nil { | ||
| return | ||
| } | ||
| }) | ||
| 
     | 
||
| ws.On(websockets.EventType_Message, func(ctx *websockets.Ctx) { | ||
| connectionStream, err := connections.Keys(context.TODO()) | ||
| if err != nil { | ||
| return | ||
| } | ||
| 
     | 
||
| senderId := ctx.Request.ConnectionID() | ||
| 
     | 
||
| for { | ||
| connectionId, err := connectionStream.Recv() | ||
| if err != nil { | ||
| break | ||
| } | ||
| 
     | 
||
| if connectionId == senderId { | ||
| continue | ||
| } | ||
| 
     | 
||
| message := fmt.Sprintf("%s: %s", senderId, ctx.Request.Message()) | ||
| err = ws.Send(context.TODO(), connectionId, []byte(message)) | ||
| if err != nil { | ||
| return | ||
| } | ||
| } | ||
| }) | ||
| 
     | 
||
| nitric.Run() | ||
| } | ||
| ``` | ||
| 
     | 
||
| </details> | ||
| 
     | 
||
| Do a quick `go mod tidy` to make sure all new dependencies are resolved. | ||
| 
     | 
||
| ## Ok, let's run this thing! | ||
| 
     | 
||
| Now that you have your WebSocket application defined with handlers for each event, it's time to test it locally. | ||
                
      
                  HomelessDinosaur marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ```bash | ||
| nitric start | ||
| ``` | ||
| 
     | 
||
| Once it starts, the application will be ready to accept WebSocket connections. You can use a WebSocket client like Postman or any other WebSocket tool to test the application. | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| We will keep it running for our tests. If you want to update your services, just save them, and they'll be reloaded automatically. | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ## Deploy to the cloud | ||
| 
     | 
||
| At this point, you can deploy what you've built to any of the supported cloud providers. To do this, start by setting up your credentials and any configuration for the cloud you prefer: | ||
| 
     | 
||
| - [AWS](/reference/providers/aws) | ||
| - [Azure](/reference/providers/azure) | ||
| - [GCP](/reference/providers/gcp) | ||
                
      
                  davemooreuws marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| Next, we'll need to create a `stack`. A stack represents a deployed instance of an application, which is a key value store of resources defined in your project. You might want separate stacks for each environment, such as stacks for `dev`, `test`, and `prod`. For now, let's start by creating a `dev` stack. | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| The `stack new` command below will create a stack named `dev` that uses the `aws` provider. | ||
| 
     | 
||
| ```bash | ||
| nitric stack new dev aws | ||
| ``` | ||
| 
     | 
||
| Continue by checking your stack file `nitric.dev.yaml` and adding in your preferred region. Let's use `us-east-1`. | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ### AWS | ||
| 
     | 
||
| Note: You are responsible for staying within the limits of the free tier or any costs associated with deployment. | ||
                
      
                  HomelessDinosaur marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| We called our stack `dev`. Let's try deploying it with the `up` command: | ||
                
      
                  raksiv marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ```bash | ||
| nitric up | ||
| ``` | ||
| 
     | 
||
| When the deployment is complete, go to the relevant cloud console and you'll be able to see and interact with your WebSocket application. | ||
                
      
                  raksiv marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| To tear down your application from the cloud, use the `down` command: | ||
| 
     | 
||
| ```bash | ||
| nitric down | ||
| ``` | ||
| 
     | 
||
| ## Summary | ||
| 
     | 
||
| In this guide, we've created a serverless WebSocket application using Go and Nitric. We've demonstrated how to set up WebSocket connections, track clients using a Key-Value store, and broadcast messages to all connected clients. This application can be easily deployed to the cloud, allowing you to build scalable, real-time communication systems. | ||
| 
     | 
||
| For more information and advanced usage, refer to the [Nitric documentation](https://nitric.io/docs). | ||
      
      Oops, something went wrong.
        
    
  
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.