I'm trying to write a wrap around a function that uses an interface{}
parameter to return data, by adding cache.
My problem is that once I have a valid interface{}
I don't know how to assign it to be returned in the parameter. The wrapped call is (github.Client) .Do
in github API client and the problem hit me when I tried to add caching with go-cache
This somewhat my function
func (c *cachedClient) requestAPI(url string, v interface{}) error {
x, found := c.cache.Get(url)
if found { // Found in cache code
log.Printf("cached: %v", x)
v = x // HERE: this do not work. x contains a valid copy of what I want but how do I store it in v?
return nil
}
req, _ := c.githubClient.NewRequest("GET", url, nil) // not found I cache, request it
res, err := c.githubClient.Do(*c.context, req, v)
if err != nil {
return err
}
if res.StatusCode != 200 {
return fmt.Errorf("Error Getting %v: %v", url, res.Status)
}
c.cache.Add(url, v, cache.DefaultExpiration) // store in cache
return nil // once here v works as expected and contain a valid item
}
It fails when has to return a cached value when I try to use it like this:
// Some init code c is a cachedClient
i := new(github.Issue)
c.requestAPI(anAPIValidURLforAnIssue, i)
log.Printf("%+v", i) // var i correctly contains an issue from the github api
o := new(github.Issue)
c.requestAPI(anAPIValidURLforAnIssue, o)
log.Printf("%+v", o) // var o should have been get from the cache but here is empty
So basically my problem is that when I correctly recover a cached item it is good but I can not store it in the parameter meant to be used to store it. I can not work with subclasses because the call I'm wrapping is using an interface{}
already. And I can not move it to return values because you can't return a generic interface. How do I make the interface{} x
be stored in v to have it available outside?
To archive what you want you need to use a bit of reflection magic. Please try to replace
v = x
with next code snippet:Note from OP: I had to add the last
.Elem()
to make this work.NOTE: in the call of the
requestAPI
method you should use a pointer to the value: let's say the cached value is of typeint
. Then you should callrequestAPI
like: