Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 4bc2a31

Browse files
committed
Apply suggestions from code review
Co-authored-by: Jye Cusch <[email protected]> Simplify project so it doesn't need an update to the nitric.yaml config. Simplify project so it doesn't need an update to the nitric.yaml config. handle errors and add consistency between guides
1 parent e0be643 commit 4bc2a31

File tree

2 files changed

+42
-44
lines changed

2 files changed

+42
-44
lines changed

docs/guides/go/realtime-messaging.mdx

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
---
2-
title_seo: Building your first WebSocket Application with Go and Nitric
32
description: Use the Nitric framework to easily build and deploy Go WebSocket applications for AWS.
43
tags:
54
- Realtime & Websockets
65
- Key Value Store
76
---
87

9-
# Building your first WebSocket Application with Nitric
8+
# Building a chat app in Go with WebSockets and Nitric
109

1110
## What we'll be doing
1211

13-
1. Use Nitric to create a WebSocket endpoint
12+
1. Use Nitric to create a WebSocket API
1413
2. Manage WebSocket connections using a Key-Value store
1514
3. Handle WebSocket events:
1615
- Register connections on connect
@@ -23,20 +22,20 @@ tags:
2322

2423
- [Go](https://go.dev/dl/)
2524
- The [Nitric CLI](/get-started/installation)
26-
- An [AWS](https://aws.amazon.com) account
25+
- An [AWS](https://aws.amazon.com) account (optional)
2726

2827
## Getting started
2928

3029
We'll start by creating a new project for our WebSocket application.
3130

3231
```bash
33-
nitric new my-websocket-app go-starter
32+
nitric new websocket-app go-starter
3433
```
3534

3635
Next, open the project in your editor of choice.
3736

3837
```bash
39-
cd my-websocket-app
38+
cd websocket-app
4039
```
4140

4241
Make sure all dependencies are resolved:
@@ -69,9 +68,9 @@ If everything is working as expected, you can now delete all files/folders in th
6968

7069
## Building the WebSocket Application
7170

72-
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:
71+
Let's begin by setting up the WebSocket application. Add a file named `main.go` to your 'services/websockets' folder, and include the following code:
7372

74-
```go
73+
```go title:services/websockets/main.go
7574
package main
7675

7776
import (
@@ -84,7 +83,7 @@ import (
8483
)
8584

8685
func main() {
87-
// Create a WebSocket endpoint named "public".
86+
// Create a WebSocket API named "public".
8887
ws := nitric.NewWebsocket("public")
8988

9089
// Initialize a KV store named "connections" with Get, Set, and Delete permissions.
@@ -98,8 +97,8 @@ func main() {
9897

9998
Here we're creating:
10099

101-
- A [WebSocket](/websockets) endpoint named `public`
102-
- A [Key-Value store](/keyvalue) named `connections` to track WebSocket connections
100+
- A [WebSocket](/websockets) API named `public`
101+
- A [Key-Value store](/keyvalue) named `connections` to track client connections
103102

104103
From here, let's add some features to that function that allow us to manage connections and broadcast messages.
105104

@@ -112,10 +111,11 @@ From here, let's add some features to that function that allow us to manage conn
112111

113112
```go
114113
ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) {
115-
err := connections.Set(context.TODO(), ctx.Request.ConnectionID(), map[string]interface{}{
114+
err := connections.Set(context.Background(), ctx.Request.ConnectionID(), map[string]interface{}{
116115
"connectionId": ctx.Request.ConnectionID(),
117116
})
118117
if err != nil {
118+
fmt.Println("Error storing connection ID in KV store:", err)
119119
return
120120
}
121121
})
@@ -125,8 +125,9 @@ ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) {
125125

126126
```go
127127
ws.On(websockets.EventType_Disconnect, func(ctx *websockets.Ctx) {
128-
err := connections.Delete(context.TODO(), ctx.Request.ConnectionID())
128+
err := connections.Delete(context.Background(), ctx.Request.ConnectionID())
129129
if err != nil {
130+
fmt.Println("Error deleting connection ID in KV store:", err)
130131
return
131132
}
132133
})
@@ -136,8 +137,9 @@ ws.On(websockets.EventType_Disconnect, func(ctx *websockets.Ctx) {
136137

137138
```go
138139
ws.On(websockets.EventType_Message, func(ctx *websockets.Ctx) {
139-
connectionStream, err := connections.Keys(context.TODO())
140+
connectionStream, err := connections.Keys(context.Background())
140141
if err != nil {
142+
fmt.Println("Error retrieving connection keys from KV store:", err)
141143
return
142144
}
143145

@@ -154,8 +156,9 @@ ws.On(websockets.EventType_Message, func(ctx *websockets.Ctx) {
154156
}
155157

156158
message := fmt.Sprintf("%s: %s", senderId, ctx.Request.Message())
157-
err = ws.Send(context.TODO(), connectionId, []byte(message))
159+
err = ws.Send(context.Background(), connectionId, []byte(message))
158160
if err != nil {
161+
fmt.Println("Error sending message to connection ID", connectionId, ":", err)
159162
return
160163
}
161164
}
@@ -167,7 +170,7 @@ ws.On(websockets.EventType_Message, func(ctx *websockets.Ctx) {
167170
<details>
168171
<summary>Your code should look like this:</summary>
169172

170-
```go
173+
```go title:services/websockets/main.go
171174
package main
172175

173176
import (
@@ -188,24 +191,27 @@ func main() {
188191

189192
// Handle new WebSocket connections by storing the connection ID in the KV store.
190193
ws.On(websockets.EventType_Connect, func(ctx *websockets.Ctx) {
191-
err := connections.Set(context.TODO(), ctx.Request.ConnectionID(), map[string]interface{}{
194+
err := connections.Set(context.Background(), ctx.Request.ConnectionID(), map[string]interface{}{
192195
"connectionId": ctx.Request.ConnectionID(),
193196
})
194197
if err != nil {
198+
fmt.Println("Error storing connection ID in KV store:", err)
195199
return
196200
}
197201
})
198202

199203
ws.On(websockets.EventType_Disconnect, func(ctx *websockets.Ctx) {
200-
err := connections.Delete(context.TODO(), ctx.Request.ConnectionID())
204+
err := connections.Delete(context.Background(), ctx.Request.ConnectionID())
201205
if err != nil {
206+
fmt.Println("Error deleting connection ID in KV store:", err)
202207
return
203208
}
204209
})
205210

206211
ws.On(websockets.EventType_Message, func(ctx *websockets.Ctx) {
207-
connectionStream, err := connections.Keys(context.TODO())
212+
connectionStream, err := connections.Keys(context.Background())
208213
if err != nil {
214+
fmt.Println("Error retrieving connection keys from KV store:", err)
209215
return
210216
}
211217

@@ -222,8 +228,9 @@ func main() {
222228
}
223229

224230
message := fmt.Sprintf("%s: %s", senderId, ctx.Request.Message())
225-
err = ws.Send(context.TODO(), connectionId, []byte(message))
231+
err = ws.Send(context.Background(), connectionId, []byte(message))
226232
if err != nil {
233+
fmt.Println("Error sending message to connection ID", connectionId, ":", err)
227234
return
228235
}
229236
}
@@ -239,36 +246,27 @@ Do a quick `go mod tidy` to make sure all new dependencies are resolved.
239246

240247
## Ok, let's run this thing!
241248

242-
Now that you have your WebSocket application defined with handlers for each event, it's time to test it locally. Update your `nitric.yaml` to point to the service at `websockets/main.go`:
243-
244-
```yaml
245-
services:
246-
- match: websockets/*
247-
runtime: go
248-
start: go run ./$SERVICE_PATH
249-
```
249+
Now that you have your WebSocket application defined with handlers for each event, it's time to test it locally.
250250

251251
```bash
252252
nitric start
253253
```
254254

255255
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. Alternatively, you can use the [Nitric Dashboard](/get-started/foundations/projects/local-development#local-dashboard).
256256

257-
We will keep it running for our tests.
258-
259257
## Deploy to the cloud
260258

261-
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 configuration for [AWS](/providers/pulumi/aws).
259+
At this point, you can deploy what you've built to any of the supported cloud providers. In this example we'll deploy to AWS. Start by setting up your credentials and configuration for the [nitric/aws provider](/providers/pulumi/aws).
262260

263-
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.
261+
Next, we'll need to create a `stack file` (deployment target). A stack is a deployed instance of an application. You might want separate stacks for each environment, such as stacks for `dev`, `test`, and `prod`. For now, let's start by creating a file for the `dev` stack.
264262

265263
The `stack new` command below will create a stack named `dev` that uses the `aws` provider.
266264

267265
```bash
268266
nitric stack new dev aws
269267
```
270268

271-
Continue by checking your stack file `nitric.dev.yaml` and adding in your preferred region. Let's use `us-east-1`.
269+
Edit the stack file `nitric.dev.yaml` and set your preferred AWS region, for example `us-east-1`.
272270

273271
### AWS
274272

@@ -277,7 +275,7 @@ Continue by checking your stack file `nitric.dev.yaml` and adding in your prefer
277275
costs associated with deployment.
278276
</Note>
279277

280-
We called our stack `dev`. Let's try deploying it with the `up` command:
278+
Let's try deploying the stack with the `up` command:
281279

282280
```bash
283281
nitric up

docs/guides/terraform/terratest.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ Our sample project creates a real-time communication service using [WebSockets](
3030

3131
We intend to deploy to AWS and will use Terratest to ensure that the following:
3232

33-
- **API Gateway WebSocket**: Confirm that the websocket endpoint is correctly configured for real-time communication.
33+
- **WebSocket API**: Confirm that the API Gateway WebSocket API is correctly configured for real-time communication.
3434
- **DynamoDB Table**: Verify that the key-value store for connections is created and operational.
3535
- **IAM Roles**: Ensure that permissions for interacting with AWS services are correctly set up.
3636

3737
Let's start by creating a new project for our application.
3838

3939
```bash
40-
nitric new my-websocket-app go-starter
40+
nitric new websocket-app go-starter
4141
```
4242

4343
### Application code
@@ -121,7 +121,7 @@ nitric stack new dev aws-tf
121121

122122
Update this newly created stack file to include your target region:
123123

124-
```yaml
124+
```yaml title:nitric.dev.yaml
125125
# The nitric provider to use
126126
provider: nitric/[email protected]
127127

@@ -131,18 +131,18 @@ region: us-east-2
131131
132132
The Nitric Terraform providers are currently in preview, to enable them you'll need to enable beta-providers in your Nitric project. You can do this by adding the following to your project's `nitric.yaml` file:
133133

134-
```
134+
```yaml title:nitric.yaml
135135
preview:
136136
- beta-providers
137137
```
138138

139-
Once you've created your Nitric stack, you can generate the Terraform code by running the following command:
139+
Once you've created your stack file, you can generate the Terraform code by running the following command:
140140

141141
```
142142
nitric up
143143
```
144144

145-
This will generate the Terraform code for your Nitric application into a folder named `cdktf.out` by default.
145+
This will generate Terraform code which can deploy your application. The output will be in a folder named `cdktf.out` by default.
146146

147147
## Add and execute Terratest
148148

@@ -170,7 +170,7 @@ touch test/terraform_resources_test.go
170170

171171
Add the following code to `terraform_resources_test.go`:
172172

173-
```go
173+
```go title:test/terraform_resources_test.go
174174
package test
175175
176176
import (
@@ -187,7 +187,7 @@ import (
187187
func TestTerraformResources(t *testing.T) {
188188
// Set Terraform options, specifying the directory with your Terraform configuration
189189
terraformOptions := &terraform.Options{
190-
TerraformDir: "../cdktf.out/stacks/my-websocket-app-dev",
190+
TerraformDir: "../cdktf.out/stacks/websocket-app-dev",
191191
}
192192
193193
// Ensure resources are destroyed after test completion
@@ -209,11 +209,11 @@ func TestTerraformResources(t *testing.T) {
209209
210210
// Test IAM role creation
211211
iamClient := iam.New(sess)
212-
roleName := "my-websocket-app_websockets-main" // Name of the IAM role to check
212+
roleName := "websocket-app_websockets-main" // Name of the IAM role to check
213213
_, err = iamClient.GetRole(&iam.GetRoleInput{
214214
RoleName: aws.String(roleName),
215215
})
216-
assert.NoError(t, err, "Expected IAM role 'my-websocket-app_websockets-main' to be created")
216+
assert.NoError(t, err, "Expected IAM role 'websocket-app_websockets-main' to be created")
217217
218218
// Test API gateway webSocket creation
219219
apiClient := apigatewayv2.New(sess)

0 commit comments

Comments
 (0)