In this part, we will be working on building the storage layer of our short URL application, so let's start!
📝 If Redis is not yet installed on your computer, you can do it following the instructions for installation with respect to your operating system.
First thing first, we will install Redis client for Golang
go get github.com/go-redis/redis/v9
then we create the store folder in the project, and two empty Go files: store.go and store_test.go
├── go.mod
├── go.sum
├── main.go
└── shortener
├── shortener.go
└── shortener_test.go
└── store
├── store.go
└── store_test.go
Now we can define wrapper structs and initialize the store service, in this case our Redis client.
package store
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
"time"
)
// StorageService is struct wrapper around raw Redis client
type StorageService struct {
redisClient *redis.Client
}
// Top level declarations for the storeService and Redis context
var (
storeService = &StorageService{}
ctx = context.Background()
)
const CacheDuration = 6 * time.Hour
// InitializeStore is initializing the store service and return a store pointer
func InitializeStore() *StorageService {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
pong, err := rdb.Ping(ctx).Result()
if err != nil {
panic(fmt.Sprintf("Error init Redis: %v", err))
}
fmt.Printf("\nRedis started successfully: pong message = {%s}", pong)
storeService.redisClient = rdb
return storeService
}
Now that our data store service has successfully been initialized, it's time to consider what storage API to offer for our shortener server.
- We want to be able to save the mapping between the original URL and the generated short URL.
- We should be able to retrieve the initial long URL once the short is provided.
As the next step let's update store.go and implement our storage API.
func SaveURLInRedis(shortURL, originalURL string) {
err := storeService.redisClient.Set(ctx, shortURL, originalURL, CacheDuration).Err()
if err != nil {
panic(fmt.Sprintf("Failed SaveURLInRedis | Error: %v - shortURL: %s - originalURL: %s\n",
err, shortURL, originalURL))
}
}
func RetrieveInitialURLFromRedis(shortURL string) string {
result, err := storeService.redisClient.Get(ctx, shortURL).Result()
if err != nil {
panic(fmt.Sprintf("Failed RetrieveInitialURLFromRedis | Error: %v - shortURL: %s\n",
err, shortURL))
}
return result
}
It was fairly straightforward. Great job!
Since we already created store_test.go file, we will set up the test shell first and then write unit test for the storage APIs.
package store
import (
"github.com/stretchr/testify/assert"
"testing"
)
var testStoreService = &StorageService{}
func init() {
testStoreService = InitializeStore()
}
func TestStoreInit(t *testing.T) {
assert.True(t, testStoreService.redisClient != nil)
}
func TestInsertionAndRetrieval(t *testing.T) {
initialLink := "https://go.dev/doc/tutorial/getting-started"
shortURL := "dysg5Fas"
// Persist data mapping
SaveURLInRedis(shortURL, initialLink)
// Retrieve initial URL
retrievedUrl := RetrieveInitialURLFromRedis(shortURL)
assert.Equal(t, initialLink, retrievedUrl)
}
📝 Don't forget to run go test ./...
to check if all your tests work as expected (✅).
As our storage service is set up, we will expose a Rest API endpoint for encoding and decoding the URLs in the next part.
Originally published at projectex.dev
Top comments (0)