cache
The cache middleware provides cache data management for Flame instances, supporting various storage backends, including memory, file, PostgreSQL, MySQL, Redis and MongoDB.
You can read source code of this middleware on GitHubopen in new window and API documentation on pkg.go.devopen in new window.
Installation
The minimum requirement of Go is 1.16.
go get github.com/flamego/cache
Storage backends
Memory
The cache.Cacher
open in new window works out-of-the-box with an optional cache.Options
open in new window and uses memory as the storage backend:
package main
import (
"net/http"
"time"
"github.com/flamego/cache"
"github.com/flamego/flamego"
)
func main() {
f := flamego.Classic()
f.Use(cache.Cacher())
f.Get("/set", func(r *http.Request, cache cache.Cache) error {
return cache.Set(r.Context(), "cooldown", true, time.Minute)
})
f.Get("/get", func(r *http.Request, cache cache.Cache) string {
v, err := cache.Get(r.Context(), "cooldown")
if err != nil && err != os.ErrNotExist {
return err.Error()
}
cooldown, ok := v.(bool)
if !ok || !cooldown {
return "It has been cooled"
}
return "Still hot"
})
f.Run()
}
Because the memory is volatile, cache data do not survive over restarts. Choose other storage backends if you need to persist cache data.
File
The cache.FileIniter
open in new window is the function to initialize a file storage backend, used together with cache.FileConfig
open in new window to customize the backend:
package main
import (
"net/http"
"os"
"path/filepath"
"time"
"github.com/flamego/cache"
"github.com/flamego/flamego"
)
func main() {
f := flamego.Classic()
f.Use(cache.Cacher(
cache.Options{
Initer: cache.FileIniter(),
Config: cache.FileConfig{
RootDir: filepath.Join(os.TempDir(), "cache"),
},
},
))
f.Get("/set", func(r *http.Request, cache cache.Cache) error {
return cache.Set(r.Context(), "cooldown", true, time.Minute)
})
f.Get("/get", func(r *http.Request, cache cache.Cache) string {
v, err := cache.Get(r.Context(), "cooldown")
if err != nil && err != os.ErrNotExist {
return err.Error()
}
cooldown, ok := v.(bool)
if !ok || !cooldown {
return "It has been cooled"
}
return "Still hot"
})
f.Run()
}
PostgreSQL
The postgres.Initer
open in new window is the function to initialize a PostgreSQL storage backend, used together with postgres.Config
open in new window to customize the backend:
package main
import (
"net/http"
"os"
"time"
"github.com/flamego/cache"
"github.com/flamego/cache/postgres"
"github.com/flamego/flamego"
)
func main() {
f := flamego.Classic()
dsn := os.ExpandEnv("postgres://$PGUSER:$PGPASSWORD@$PGHOST:$PGPORT/$PGDATABASE?sslmode=$PGSSLMODE")
f.Use(cache.Cacher(
cache.Options{
Initer: postgres.Initer(),
Config: postgres.Config{
DSN: dsn,
Table: "cache",
InitTable: true,
},
},
))
f.Get("/set", func(r *http.Request, cache cache.Cache) error {
return cache.Set(r.Context(), "cooldown", true, time.Minute)
})
f.Get("/get", func(r *http.Request, cache cache.Cache) string {
v, err := cache.Get(r.Context(), "cooldown")
if err != nil && err != os.ErrNotExist {
return err.Error()
}
cooldown, ok := v.(bool)
if !ok || !cooldown {
return "It has been cooled"
}
return "Still hot"
})
f.Run()
}
MySQL
The mysql.Initer
open in new window is the function to initialize a MySQL storage backend, used together with mysql.Config
open in new window to customize the backend:
package main
import (
"net/http"
"os"
"time"
"github.com/flamego/cache"
"github.com/flamego/cache/mysql"
"github.com/flamego/flamego"
)
func main() {
f := flamego.Classic()
dsn := os.ExpandEnv("$MYSQL_USER:$MYSQL_PASSWORD@tcp($MYSQL_HOST:$MYSQL_PORT)/$MYSQL_DATABASE?charset=utf8&parseTime=true")
f.Use(cache.Cacher(
cache.Options{
Initer: mysql.Initer(),
Config: mysql.Config{
DSN: dsn,
Table: "cache",
InitTable: true,
},
},
))
f.Get("/set", func(r *http.Request, cache cache.Cache) error {
return cache.Set(r.Context(), "cooldown", true, time.Minute)
})
f.Get("/get", func(r *http.Request, cache cache.Cache) string {
v, err := cache.Get(r.Context(), "cooldown")
if err != nil && err != os.ErrNotExist {
return err.Error()
}
cooldown, ok := v.(bool)
if !ok || !cooldown {
return "It has been cooled"
}
return "Still hot"
})
f.Run()
}
Redis
The redis.Initer
open in new window is the function to initialize a Redis storage backend, used together with redis.Config
open in new window to customize the backend:
package main
import (
"net/http"
"os"
"time"
"github.com/flamego/cache"
"github.com/flamego/cache/redis"
"github.com/flamego/flamego"
)
func main() {
f := flamego.Classic()
f.Use(cache.Cacher(
cache.Options{
Initer: redis.Initer(),
Config: redis.Config{
Options: &redis.Options{
Addr: os.ExpandEnv("$REDIS_HOST:$REDIS_PORT"),
DB: 15,
},
},
},
))
f.Get("/set", func(r *http.Request, cache cache.Cache) error {
return cache.Set(r.Context(), "cooldown", true, time.Minute)
})
f.Get("/get", func(r *http.Request, cache cache.Cache) string {
v, err := cache.Get(r.Context(), "cooldown")
if err != nil && err != os.ErrNotExist {
return err.Error()
}
cooldown, ok := v.(bool)
if !ok || !cooldown {
return "It has been cooled"
}
return "Still hot"
})
f.Run()
}
MongoDB
The mongo.Initer
open in new window is the function to initialize a MongoDB storage backend, used together with mongo.Config
open in new window to customize the backend:
package main
import (
"net/http"
"os"
"time"
"github.com/flamego/cache"
"github.com/flamego/cache/mongo"
"github.com/flamego/flamego"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
f := flamego.Classic()
f.Use(cache.Cacher(
cache.Options{
Initer: mongo.Initer(),
Config: mongo.Config{
Options: options.Client().ApplyURI(os.Getenv("MONGODB_URI")),
Database: os.Getenv("MONGODB_DATABASE"),
Collection: "cache",
},
},
))
f.Get("/set", func(r *http.Request, cache cache.Cache) error {
return cache.Set(r.Context(), "cooldown", true, time.Minute)
})
f.Get("/get", func(r *http.Request, cache cache.Cache) string {
v, err := cache.Get(r.Context(), "cooldown")
if err != nil && err != os.ErrNotExist {
return err.Error()
}
cooldown, ok := v.(bool)
if !ok || !cooldown {
return "It has been cooled"
}
return "Still hot"
})
f.Run()
}
Supported value types
The default encoder and decoder of cache data use gobopen in new window, and only limited types are supported for values. When you encounter errors like encode: gob: type not registered for interface: time.Duration
, you can use gob.Register
open in new window to register the type for encoding and decoding.
For example:
gob.Register(time.Duration(0))
You only need to regsiter once for the entire lifecyle of your application.