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

Commit eb8bddb

Browse files
raksivdavemooreuws
andauthored
update guide to v1 and use keyvalue (#598)
Co-authored-by: David Moore <[email protected]>
1 parent d9c778e commit eb8bddb

File tree

1 file changed

+44
-61
lines changed

1 file changed

+44
-61
lines changed

src/pages/guides/go/serverless-rest-api-example.mdx

Lines changed: 44 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ export const description =
33

44
export const title_meta = 'Building your first API with Go and Nitric'
55

6-
<Note>
7-
This guide is for v0, v1 is in development. Interested in contributing or
8-
chatting with us? [Get in touch!](https://nitric.io/chat)
9-
</Note>
10-
116
# Building your first API with Nitric
127

138
## What we'll be doing
@@ -44,7 +39,7 @@ export const title_meta = 'Building your first API with Go and Nitric'
4439
We'll start by creating a new project for our API.
4540

4641
```bash
47-
nitric new my-profile-api "official/Go - Starter (experimental)"
42+
nitric new my-profile-api go-starter
4843
```
4944

5045
Next, open the project in your editor of choice.
@@ -62,13 +57,14 @@ go mod tidy
6257
The scaffolded project should have the following structure:
6358

6459
```text
65-
+--functions/
60+
+--services/
6661
| +-- hello/
6762
| +-- main.go
6863
| ...
6964
+--nitric.yaml
7065
+--go.mod
7166
+--go.sum
67+
+--golang.dockerfile
7268
+--.gitignore
7369
+--README.md
7470
```
@@ -79,31 +75,23 @@ You can test the project to verify everything is working as expected:
7975
nitric start
8076
```
8177

82-
and in a separate terminal:
83-
84-
```bash
85-
go run functions/hello
86-
```
87-
88-
<Note>
89-
The first command starts the Nitric Server using `nitric start`, which
90-
provides local interfaces to emulate cloud resources. Then `go run
91-
functions/hello` runs your functions and allows them to connect.
92-
</Note>
93-
94-
If everything is working as expected you can now delete all files in the `functions/` folder, we'll create new functions in this guide.
78+
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.
9579

9680
## Building the Profile API
9781

98-
Let's start building the profiles API. Create a file named `main.go` in the functions directory and add the following:
82+
Let's begin by setting up the Profiles API. First, create a new folder called `profiles` within the services directory. Inside this folder, add a file named `main.go`, and include the following code:
9983

10084
```go
10185
package main
10286

10387
import (
104-
"fmt"
88+
"context"
89+
"encoding/json"
90+
"fmt"
10591

106-
"github.com/nitrictech/go-sdk/nitric"
92+
"github.com/google/uuid"
93+
"github.com/nitrictech/go-sdk/handler"
94+
"github.com/nitrictech/go-sdk/nitric"
10795
)
10896

10997
func main() {
@@ -112,7 +100,7 @@ func main() {
112100
return
113101
}
114102

115-
profiles, err := nitric.NewCollection("profiles").With(nitric.CollectionReading, nitric.CollectionWriting)
103+
profiles, err := nitric.NewKv("profiles").Allow(nitric.KvStoreGet, nitric.KvStoreSet)
116104
if err != nil {
117105
return
118106
}
@@ -126,20 +114,20 @@ func main() {
126114
Here we're creating:
127115

128116
- An API named `public`,
129-
- A collection named `profiles` and giving our function permission to read and write to that collection.
117+
- A key value store named `profiles` and giving our function permission to read and write to that key value store.
130118

131119
From here, let's add some features to that function that allow us to work with profiles.
132120

133121
<Note>
134122
You could separate some or all of these request handlers into their own
135-
functions if you prefer. For simplicity we'll group them together in this
123+
services if you prefer. For simplicity we'll group them together in this
136124
guide.
137125
</Note>
138126

139127
### Create profiles with POST
140128

141129
```go
142-
profilesApi.Post("/profiles", func(ctx *faas.HttpContext, next faas.HttpHandler) (*faas.HttpContext, error) {
130+
profilesApi.Post("/profiles", func(ctx *handler.HttpContext, next handler.HttpHandler) (*handler.HttpContext, error) {
143131
id := uuid.New().String()
144132

145133
var profileRequest map[string]interface{}
@@ -148,7 +136,7 @@ profilesApi.Post("/profiles", func(ctx *faas.HttpContext, next faas.HttpHandler)
148136
return ctx, err
149137
}
150138

151-
err = profiles.Doc(id).Set(ctx.Request.Context(), profileRequest)
139+
err = profiles.Set(context.Background(), id, profileRequest)
152140
if err != nil {
153141
return ctx, err
154142
}
@@ -162,18 +150,18 @@ profilesApi.Post("/profiles", func(ctx *faas.HttpContext, next faas.HttpHandler)
162150
### Retrieve a profile with GET
163151

164152
```go
165-
profilesApi.Get("/profiles/:id", func(ctx *faas.HttpContext, next faas.HttpHandler) (*faas.HttpContext, error) {
153+
profilesApi.Get("/profiles/:id", func(ctx *handler.HttpContext, next handler.HttpHandler) (*handler.HttpContext, error) {
166154
id := ctx.Request.PathParams()["id"]
167155

168-
profile, err := profiles.Doc(id).Get(ctx.Request.Context())
156+
profile, err := profiles.Get(context.Background(), id)
169157
if err != nil {
170158
ctx.Response.Status = 404
171159
ctx.Response.Body = []byte(fmt.Sprintf("profile with id '%s' not found", id))
172160

173161
return ctx, nil
174162
}
175163

176-
ctx.Response.Body, err = json.Marshal(profile.Content())
164+
ctx.Response.Body, err = json.Marshal(profile)
177165

178166
return ctx, err
179167
})
@@ -182,15 +170,20 @@ profilesApi.Get("/profiles/:id", func(ctx *faas.HttpContext, next faas.HttpHandl
182170
### List all profiles with GET
183171

184172
```go
185-
profilesApi.Get("/profiles", func(ctx *faas.HttpContext, next faas.HttpHandler) (*faas.HttpContext, error) {
186-
profiles, err := profiles.Query().Fetch(ctx.Request.Context())
173+
profilesApi.Get("/profiles", func(ctx *handler.HttpContext, next handler.HttpHandler) (*handler.HttpContext, error) {
174+
keys, err := profiles.Keys(context.TODO())
187175
if err != nil {
188176
return ctx, err
189177
}
190178

191179
var profileContent []map[string]interface{}
192-
for _, doc := range profiles.Documents {
193-
profileContent = append(profileContent, doc.Content())
180+
for {
181+
key, err := keys.Recv()
182+
if err != nil {
183+
break
184+
}
185+
content, _ := profiles.Get(context.Background(), key)
186+
profileContent = append(profileContent, content)
194187
}
195188

196189
ctx.Response.Body, err = json.Marshal(profileContent)
@@ -202,10 +195,10 @@ profilesApi.Get("/profiles", func(ctx *faas.HttpContext, next faas.HttpHandler)
202195
### Remove a profile with DELETE
203196

204197
```go
205-
profilesApi.Delete("/profile/:id", func(ctx *faas.HttpContext, next faas.HttpHandler) (*faas.HttpContext, error) {
198+
profilesApi.Delete("/profiles/:id", func(ctx *handler.HttpContext, next handler.HttpHandler) (*handler.HttpContext, error) {
206199
id := ctx.Request.PathParams()["id"]
207200

208-
err := profiles.Doc(id).Delete(ctx.Request.Context())
201+
err := profiles.Delete(context.Background(), id)
209202
if err != nil {
210203
ctx.Response.Status = 404
211204
ctx.Response.Body = []byte(fmt.Sprintf("profile with id '%s' not found", id))
@@ -217,6 +210,8 @@ profilesApi.Delete("/profile/:id", func(ctx *faas.HttpContext, next faas.HttpHan
217210
})
218211
```
219212

213+
Do a quick `go mod tidy` to make sure all new dependencies are resolved.
214+
220215
## Ok, let's run this thing!
221216

222217
Now that you have an API defined with handlers for each of its methods, it's time to test it locally.
@@ -225,15 +220,9 @@ Now that you have an API defined with handlers for each of its methods, it's tim
225220
nitric start
226221
```
227222

228-
and in a separate terminal:
229-
230-
```bash
231-
go run functions/hello
232-
```
233-
234223
Once it starts, the application will receive requests via the API port. You can use cURL, Postman or any other HTTP client to test the API.
235224

236-
We will keep it running for our tests. If you want to update your functions, just save them, they'll be reloaded automatically.
225+
We will keep it running for our tests. If you want to update your services, just save them, they'll be reloaded automatically.
237226

238227
## Test your API
239228

@@ -277,17 +266,15 @@ At this point, you can deploy what you've built to any of the supported cloud pr
277266
- [Azure](/reference/providers/azure)
278267
- [GCP](/reference/providers/gcp)
279268

280-
Next, we'll need to create a `stack`. A stack represents a deployed instance of an application, which is a collection 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.
269+
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.
270+
271+
The `stack new` command below will create a stack named `dev` that uses the `aws` provider.
281272

282273
```bash
283-
nitric stack new
274+
nitric stack new dev aws
284275
```
285276

286-
```
287-
? What should we name this stack? dev
288-
? Which provider do you want to deploy with? aws
289-
? Which region should the stack deploy to? us-east-1
290-
```
277+
Continue by checking your stack file `nitric.dev.yaml` and adding in your preferred region, let's use `us-east-1`.
291278

292279
### AWS
293280

@@ -297,10 +284,6 @@ We called our stack `dev`, let's try deploying it with the `up` command
297284

298285
```bash
299286
nitric up
300-
┌───────────────────────────────────────────────────────────────┐
301-
| API | Endpoint |
302-
| main | https://XXXXXXXX.execute-api.us-east-1.amazonaws.com |
303-
└───────────────────────────────────────────────────────────────┘
304287
```
305288

306289
When the deployment is complete, go to the relevant cloud console and you'll be able to see and interact with your API.
@@ -317,10 +300,10 @@ If you want to go a bit deeper and create some other resources with Nitric, why
317300

318301
### Access profile buckets with permissions
319302

320-
Define a bucket named `profilesImg` with reading/writing permissions
303+
Define a bucket named `profileImages` with read/write permissions
321304

322305
```go
323-
profileImages, err := nitric.NewBucket("profileImages").With(nitric.BucketReading, nitric.BucketWriting)
306+
profileImages, err := nitric.NewBucket("profileImages").Allow(nitric.BucketRead, nitric.BucketWrite)
324307
if err != nil {
325308
fmt.Println(err)
326309
return
@@ -330,11 +313,11 @@ if err != nil {
330313
### Get a URL to upload a profile image
331314

332315
```go
333-
profilesApi.Get("/profiles/:id/image/upload", func(ctx *faas.HttpContext, next faas.HttpHandler) (*faas.HttpContext, error) {
316+
profilesApi.Get("/profiles/:id/image/upload", func(ctx *handler.HttpContext, next handler.HttpHandler) (*handler.HttpContext, error) {
334317
id := ctx.Request.PathParams()["id"]
335318
photoId := fmt.Sprintf("images/%s/photo.png", id)
336319

337-
photoUrl, err := profileImages.File(photoId).UploadUrl(ctx.Request.Context(), 600)
320+
photoUrl, err := profileImages.File(photoId).UploadUrl(context.TODO(), 600)
338321
if err != nil {
339322
return ctx, err
340323
}
@@ -348,11 +331,11 @@ profilesApi.Get("/profiles/:id/image/upload", func(ctx *faas.HttpContext, next f
348331
### Get a URL to download a profile image
349332

350333
```go
351-
profilesApi.Get("/profiles/:id/image/download", func(ctx *faas.HttpContext, next faas.HttpHandler) (*faas.HttpContext, error) {
334+
profilesApi.Get("/profiles/:id/image/download", func(ctx *handler.HttpContext, next handler.HttpHandler) (*handler.HttpContext, error) {
352335
id := ctx.Request.PathParams()["id"]
353336
photoId := fmt.Sprintf("images/%s/photo.png", id)
354337

355-
photoUrl, err := profileImages.File(photoId).DownloadUrl(ctx.Request.Context(), 600)
338+
photoUrl, err := profileImages.File(photoId).DownloadUrl(context.TODO(), 600)
356339
if err != nil {
357340
return ctx, err
358341
}

0 commit comments

Comments
 (0)