cache
The cache middleware provides cache data management for Flame instances, supporting various storage backends, including memory, file, PostgreSQL, MySQL, Redis, MongoDB and SQLite.
You can read source code of this middleware on GitHub and API documentation on pkg.go.dev.
Installation
go get github.com/flamego/cache
Storage backends
Memory
The cache.Cacher
works out-of-the-box with an optional cache.Options
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
is the function to initialize a file storage backend, used together with cache.FileConfig
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
is the function to initialize a PostgreSQL storage backend, used together with postgres.Config
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
is the function to initialize a MySQL storage backend, used together with mysql.Config
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
is the function to initialize a Redis storage backend, used together with redis.Config
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
is the function to initialize a MongoDB storage backend, used together with mongo.Config
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()
}
SQLite
The sqlite.Initer
is the function to initialize a SQLite storage backend, used together with sqlite.Config
to customize the backend:
package main
import (
"net/http"
"os"
"time"
"github.com/flamego/cache"
"github.com/flamego/cache/sqlite"
"github.com/flamego/flamego"
)
func main() {
f := flamego.Classic()
f.Use(cache.Cacher(
cache.Options{
Initer: sqlite.Initer(),
Config: sqlite.Config{
DSN: "app.db",
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()
}
Supported value types
The default encoder and decoder of cache data use gob, 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
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.