/gin-cache

gin easy to use memCache and redisCache

Primary LanguageGoMIT LicenseMIT

Release doc Build Status Go Report Card codecov

Gin cache middleware

Easy use of caching with Gin Handler Func

Driver

  • memory
  • redis
  • more...

Install

go get -u github.com/pygzfei/gin-cache

Quick start

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/pygzfei/gin-cache/cmd/startup"
	"github.com/pygzfei/gin-cache/pkg/define"
	"time"
)

func main() {

	cache, _ := startup.MemCache()
	r := gin.Default()

	r.GET("/ping", cache.Handler(
		define.Caching{
		    Cacheable: []define.Cacheable{
                    // params["id"] is the request data from query or post data, for example: 
                    // http://domain/?id=1, the cache will be generated as: `anson:id:1`
                    {GenKey: func(params map[string]interface{}) string {
                        return fmt.Sprintf("anson:id:%s", params["id"])
                    }},
			},
		},
		func(c *gin.Context) {
			c.JSON(200, gin.H{
				"message": "pong", // The returned data will be cached
			})
		},
	))

	r.Run()
}

Overwrite global cache time

cache, _ := startup.MemCache()

r := gin.Default()

r.GET("/ping_for_timeout", cache.Handler(
    define.Caching{
        Cacheable: []define.Cacheable{
            {GenKey: func(params map[string]interface{}) string {
                return fmt.Sprintf("anson:id:%s&name=%s", item.Id, item.Hash)
            }, 
            // The effective time of the cache will be based on this time value instead of the global value
            CacheTime: time.Second },
        },
    },
    func(c *gin.Context) {
       // ...
    },
))

Trigger Cache evict

// Post Body Json: {"id": 1}
// The cache key value that will trigger invalidation is: `anson:userid:1`
r.POST("/ping", cache.Handler(
    define.Caching{
        Evict: []define.CacheEvict{
            // params["id"]  from Post Body Json `{"id": 1}`
            func(params map[string]interface{}) string {
                return fmt.Sprintf("anson:id:%s", params["id"])
            },
        },
    },
    func(c *gin.Context) {
        // ...
    },
))

// Wildcards '*' can also be used, e.g. 'anson:id:1*'
// If this data exists in the cache list: ["anson:id:1", "anson:id:12", "anson:id:3"]
// Then the cached data starting with `anson:id:1` will be deleted, and the cache list will remain: ["anson:id:3"]
r.POST("/ping", cache.Handler(
    define.Caching{
        Evict: []define.CacheEvict{
            func(params map[string]interface{}) string {
                return fmt.Sprintf("anson:id:%s*", params["id"])
            },
        },
    },
    func(c *gin.Context) {
        // ...
    },
))

Use Redis

cache, _ := startup.RedisCache(time.Second*30, &redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
})
	

Hooks

cache instance, returns "application/json; Charset=utf-8" by default

ctx.Writer.Header().Set("Content-Type", "application/json; Charset=utf-8")
ctx.String(http.StatusOK, cacheValue)
ctx.Abort()

also, can use the global Hook to intercept the return information

cache, _ := startup.MemCache(timeout, func(c *gin.Context, cacheValue string) {
    // cached value, which can be intercepted globally
})

also, use a separate Hook to intercept a message return

cache, _ := startup.MemCache(timeout, func(c *gin.Context, cacheValue string) {
    // will not be executed here
})

r.GET("/pings", cache.Handler(
    define.Caching{
        Cacheable: []define.Cacheable{
            GenKey: func(params map[string]interface{}) string {
                return fmt.Sprintf("anson:userId:%s hash:%s", params["id"], params["hash"])
            },
             onCacheHit: define.CacheHitHook{func(c *gin.Context, cacheValue string) {
                // this will override the global interception of the cache
                assert.True(t, len(cacheValue) > 0)
            }}},
        },
    },
    func(c *gin.Context) {
       //...
    },
))