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

Commit bd46e95

Browse files
raksivdavemooreuws
andauthored
Add url shortener guide for GO (#689)
Co-authored-by: David Moore <[email protected]>
1 parent 36763c2 commit bd46e95

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-0
lines changed

dictionary.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ roadmap
8484
scaffolded
8585
scalable
8686
serverless
87+
shortener
88+
struct
8789
transcoding
8890
triages
8991
undeploy

docs/guides/go/url-shortner.mdx

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
---
2+
description: Use the Nitric framework to build and deploy a URL shortening service in Go.
3+
tags:
4+
- Key Value Store
5+
- API
6+
languages:
7+
- go
8+
start_steps: |
9+
git clone --depth 1 https://github.com/nitrictech/examples
10+
cd examples/v1/url-shortener
11+
go mod tidy
12+
nitric start
13+
published_at: 2024-12-24
14+
---
15+
16+
# Building a URL shortener in Go with Nitric
17+
18+
## What we'll be doing
19+
20+
1. Use Nitric to create a simple URL shortener service.
21+
2. Expose an HTTP endpoint for shortening URLs.
22+
3. Store shortened URLs in a Key-Value (KV) store.
23+
4. Redirect users to the original URL when accessing the short code.
24+
5. Run locally for testing.
25+
6. Deploy to AWS.
26+
27+
## Prerequisites
28+
29+
- [Go](https://go.dev/dl/)
30+
- The [Nitric CLI](/get-started/installation)
31+
- An [AWS](https://aws.amazon.com) account (optional)
32+
33+
## Getting started
34+
35+
We'll start by creating a new project for our WebSocket application. The finished source can be found [here](https://github.com/nitrictech/examples/tree/main/v1/url-shortener).
36+
37+
```bash
38+
nitric new url-shortener go-starter
39+
```
40+
41+
Next, open the project in your preferred editor:
42+
43+
```bash
44+
cd url-shortener
45+
```
46+
47+
Make sure all dependencies are resolved:
48+
49+
```bash
50+
go mod tidy
51+
```
52+
53+
The scaffolded project should have the following structure:
54+
55+
```text
56+
+--services/
57+
| +-- hello/
58+
| +-- main.go
59+
+--nitric.yaml
60+
+--go.mod
61+
+--go.sum
62+
+--golang.dockerfile
63+
+--.gitignore
64+
+--README.md
65+
```
66+
67+
You can test the project to ensure everything is working as expected:
68+
69+
```bash
70+
nitric start
71+
```
72+
73+
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.
74+
75+
### Resource Initialization
76+
77+
We'll start by creating a `resources` package that defines and initializes the API and KV store from the Nitric SDK. At this point, we won't request any permissions like `get` or `set` for the KV store. We'll do that in the individual services to ensure least privilege provisioning.
78+
79+
```go title:resources/main.go
80+
package resources
81+
82+
import (
83+
"sync"
84+
85+
"github.com/nitrictech/go-sdk/nitric"
86+
"github.com/nitrictech/go-sdk/nitric/apis"
87+
"github.com/nitrictech/go-sdk/nitric/keyvalue"
88+
)
89+
90+
type Resource struct {
91+
MainApi apis.Api
92+
UrlKvStore keyvalue.KvStore
93+
}
94+
95+
var (
96+
resource *Resource
97+
resourceOnce sync.Once
98+
)
99+
100+
func Get() *Resource {
101+
resourceOnce.Do(func() {
102+
mainApi := nitric.NewApi("main")
103+
104+
resource = &Resource{
105+
MainApi: mainApi,
106+
UrlKvStore: nitric.NewKv("urls"),
107+
}
108+
})
109+
110+
return resource
111+
}
112+
```
113+
114+
## Building the URL Shortener Application
115+
116+
Create a new folder called `shortener` within the `services` directory. Inside this folder, add a file named `main.go`, and include the following code:
117+
118+
```go title:services/shortener/main.go
119+
package main
120+
121+
import (
122+
"math/rand"
123+
124+
"github.com/nitrictech/go-sdk/nitric"
125+
"github.com/nitrictech/go-sdk/nitric/apis"
126+
"github.com/nitrictech/go-sdk/nitric/keyvalue"
127+
"github.com/nitrictech/templates/go-starter/resources"
128+
)
129+
130+
func main() {
131+
// Initialize the resources defined in resources.go
132+
urlKvStore := resources.Get().UrlKvStore.Allow(keyvalue.KvStoreSet, keyvalue.KvStoreGet)
133+
134+
// POST /shorten - Shorten a given URL
135+
resources.Get().MainApi.Post("/shorten", func(ctx *apis.Ctx) {
136+
// TODO: implement app logic
137+
})
138+
139+
// GET /:code - Redirect to the original URL associated with the short code
140+
resources.Get().MainApi.Get("/:code", func(ctx *apis.Ctx) {
141+
// TODO: implement app logic
142+
})
143+
144+
nitric.Run()
145+
}
146+
```
147+
148+
Here we're creating placeholders for our API routes and initializing our KV store with permissions so we can `GET` and `SET` values.
149+
150+
Next, let's add a helper function to handle URL shortening and an inline struct to hold our URL data.
151+
152+
```go title:services/shortener/main.go
153+
func generateShortCode() string {
154+
s := ""
155+
for i := 0; i < 6; i++ {
156+
s += string(rand.Intn(26) + 97) // Generate a lowercase letter
157+
}
158+
159+
return s
160+
}
161+
162+
var shortenData struct {
163+
Url string `json:"url"`
164+
}
165+
```
166+
167+
Let's implement our shorten route:
168+
169+
```go title:services/shortener/main.go
170+
// POST /shorten - Shorten a given URL
171+
resources.Get().MainApi.Post("/shorten", func(ctx *apis.Ctx) {
172+
err := json.Unmarshal(ctx.Request.Data(), &shortenData)
173+
if err != nil || strings.TrimSpace(shortenData.Url) == "" {
174+
ctx.Response.Status = http.StatusBadRequest
175+
ctx.Response.Body = []byte("Invalid or missing URL")
176+
return
177+
}
178+
179+
shortCode := generateShortCode()
180+
// Store the mapping of short code -> original URL
181+
err = urlKvStore.Set(context.Background(), shortCode, map[string]interface{}{
182+
"url": shortenData.Url,
183+
})
184+
if err != nil {
185+
ctx.Response.Status = 500
186+
ctx.Response.Body = []byte("Error shortening URL")
187+
return
188+
}
189+
190+
// Extract the origin from headers (for demonstration), then return the short URL
191+
origin := ""
192+
if val, ok := ctx.Request.Headers()["X-Forwarded-For"]; ok {
193+
origin = val[0]
194+
} else if val, ok := ctx.Request.Headers()["x-forwarded-for"]; ok {
195+
origin = val[0]
196+
}
197+
198+
ctx.Response.Body = []byte(fmt.Sprintf("%s/%s", origin, shortCode))
199+
})
200+
```
201+
202+
Finally, we'll add a redirect handler to send users to the long URL when they use the short code:
203+
204+
```go title:services/shortener/main.go
205+
// GET /:code - Redirect to the original URL associated with the short code
206+
resources.Get().MainApi.Get("/:code", func(ctx *apis.Ctx) {
207+
code := ctx.Request.PathParams()["code"]
208+
209+
data, err := urlKvStore.Get(context.Background(), code)
210+
if err == nil {
211+
ctx.Response.Headers["Location"] = []string{data["url"].(string)}
212+
ctx.Response.Status = 301
213+
} else {
214+
fmt.Println("Error getting URL: ", err)
215+
ctx.Response.Status = 404
216+
}
217+
})
218+
```
219+
220+
## Running locally
221+
222+
Ensure all dependencies are resolved and start the project:
223+
224+
```bash
225+
go mod tidy
226+
nitric start
227+
```
228+
229+
Nitric will run the service locally. You can test the endpoints using tools like `curl` or Postman. For example, to shorten a URL:
230+
231+
```bash
232+
curl -X POST localhost:4001/shorten -d '{"url":"https://example.com"}' -H "Content-Type: application/json"
233+
```
234+
235+
You should receive a response containing the short code which you can use in a browser to test the redirect:
236+
237+
```
238+
http://localhost:4001/{shortcode}
239+
```
240+
241+
## Deploy to the Cloud
242+
243+
When you're ready to deploy this to the cloud, Nitric makes it straightforward. In this example, we’ll deploy to AWS. First, set up your credentials and configuration for the [nitric/aws provider](/providers/pulumi/aws).
244+
245+
### Create a Stack
246+
247+
Create a `dev` stack that uses the `aws` provider:
248+
249+
```bash
250+
nitric stack new dev aws
251+
```
252+
253+
This command creates a `nitric.dev.yaml` file defining your deployment target. Edit it to configure your preferred AWS region (e.g., `us-east-1`).
254+
255+
### Deploying
256+
257+
Deploy the stack to the cloud:
258+
259+
```bash
260+
nitric up
261+
```
262+
263+
Once deployment is complete, you’ll have live endpoints accessible via AWS infrastructure. Test the endpoints using the new domain provided after deployment.
264+
265+
To remove deployed resources:
266+
267+
```bash
268+
nitric down
269+
```
270+
271+
## Summary
272+
273+
In this guide, we’ve built a simple URL shortening service using Go and Nitric. We’ve shown how to:
274+
275+
- Set up an API to shorten URLs and redirect users.
276+
- Use a Key-Value store to persist short code mappings.
277+
- Run and test the application locally before deploying it to AWS.

0 commit comments

Comments
 (0)