Redis CRUD Operations with JSON Serialization¶
This guide outlines how to perform basic CRUD (Create, Read, Update, Delete) operations on a Redis database using the Go programming language, utilizing JSON serialization to manage structured data^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
Overview¶
When building microservices, it is common to need a persistent storage layer that can handle structured data. While file-based storage (like JSON files) is useful for learning, it presents challenges for concurrency and state management. Redis is often used to decouple state from the application^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
In this context, data is stored as serialized JSON strings within Redis keys. This allows complex objects, such as a video struct containing metadata (ID, title, URL, etc.), to be persisted and retrieved efficiently^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
Prerequisites¶
To interact with Redis in Go, the go-redis client library is required^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
go get github.com/go-redis/redis/v8
You will also need to establish a connection to your Redis instance using a client, typically configured with environment variables for host, port, and password^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
Data Structure¶
The operations below assume a struct definition representing the entity to be stored. For example, a video struct^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md]:
type video struct {
Id string
Title string
Description string
Imageurl string
Url string
}
Create / Update Operation¶
Data is stored in Redis by first serializing the Go struct into a JSON byte array, and then saving it using the SET command^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md]. Since Redis keys are unique, using SET with an existing ID effectively acts as an Update operation^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
func saveVideo(video video) {
// 1. Marshal the struct into JSON
videoBytes, err := json.Marshal(video)
if err != nil {
panic(err)
}
// 2. Set the key (video.Id) to the JSON value
err = redisClient.Set(ctx, video.Id, videoBytes, 0).Err()
if err != nil {
panic(err)
}
}
To save a list of items, iterate over the slice and call the single-record save function for each item^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
Read Operation¶
Reading data involves retrieving the value for a specific key (usually the entity's ID) from Redis, and then deserializing the resulting JSON string back into a Go struct^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
func getVideo(id string) (video, error) {
// 1. Get the value from Redis
val, err := redisClient.Get(ctx, id).Result()
if err == redis.Nil {
return video{}, fmt.Errorf("video not found") // Handle empty result
} else if err != nil {
return video{}, err // Handle connection errors
}
// 2. Unmarshal JSON into the struct
var v video
err = json.Unmarshal([]byte(val), &v)
if err != nil {
panic(err)
}
return v, nil
}
To retrieve all records, you can use the KEYS command to find all matching keys and then iterate over them to fetch each object individually^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
HTTP Handler Integration¶
These CRUD functions are typically integrated into HTTP handlers to create a RESTful API^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
Get Single or All Videos¶
A single GET endpoint can handle fetching a specific video by ID or returning all videos if no ID is provided^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
func HandleGetVideos(w http.ResponseWriter, r *http.Request) {
// Check for 'id' query parameter
id, ok := r.URL.Query()["id"]
if ok {
// Return single video
video, err := getVideo(id[0])
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
videoBytes, _ := json.Marshal(video)
w.Write(videoBytes)
return
}
// Return all videos
videos := getVideos() // Implementation using KEYS command
videoBytes, _ := json.Marshal(videos)
w.Write(videoBytes)
}
Update Videos¶
The update handler accepts JSON data in the request body, unmarshals it, and saves it to Redis^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md].
func HandleUpdateVideos(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
body, _ := ioutil.ReadAll(r.Body)
// Check if updating a single video
_, ok := r.URL.Query()["id"]
if ok {
var video video
json.Unmarshal(body, &video)
saveVideo(video)
return
}
// Otherwise, update list (bulk)
var videos []video
json.Unmarshal(body, &videos)
saveVideos(videos)
}
}
Related Concepts¶
- [[流程化筆記]]: Documenting the specific steps of connecting to the database and handling serialization prevents errors during implementation.
- 20/80學習原則: Learning the basic
SETandGETcommands (the 20%) covers the majority of simple use cases for Redis. - [[23种经典设计模式]]: The Repository pattern is often used to encapsulate the data access logic shown here.
Sources¶
^[400-devops__09-Scripting-Language__golang__introduction__part-5.database.redis__readme.md]