Skip to content

Commit a53e265

Browse files
committed
don't remember what I fixed, but it's a little better now
1 parent 436406e commit a53e265

File tree

10 files changed

+135
-81
lines changed

10 files changed

+135
-81
lines changed

.github/workflows/tests.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,10 @@ jobs:
2424
cache-dependency-path: |
2525
go.sum
2626
27-
- name: Start Todo Server
28-
run: |
29-
go run test_api/todo/server.go &
30-
go run main.go &
31-
go install github.com/bitnami/wait-for-port
32-
wait-for-port 8080
33-
wait-for-port 9090
34-
go test -v ./...
35-
36-
- name: Wait for Todo Server
27+
- name: Start Servers and Run Tests
3728
run: |
29+
go run test_api/todo/server.go & go run main.go & sleep 10
3830
go install github.com/bitnami/wait-for-port
3931
wait-for-port 8080 --timeout=60
4032
wait-for-port 9090 --timeout=60
41-
42-
- name: Run Tests
43-
run: |
4433
go test -v ./...

api/handlers/cache_handlers.go

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ package handlers
33
import (
44
"bytes"
55
"encoding/json"
6+
"fmt"
67
"graphql_cache/config"
78
"graphql_cache/graphcache"
89
"io"
9-
"log"
1010
"net/http"
1111
"net/url"
1212
"time"
@@ -19,13 +19,13 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
1919
// Create a new HTTP request with the same method, URL, and body as the original request
2020
targetURL, err := url.Parse(cfg.Origin)
2121
if err != nil {
22-
log.Println(err)
22+
fmt.Println(err)
2323
http.Error(w, "Error parsing target URL", http.StatusInternalServerError)
2424
}
2525

2626
proxyReq, err := http.NewRequest(r.Method, targetURL.String(), r.Body)
2727
if err != nil {
28-
log.Println(err)
28+
fmt.Println(err)
2929
http.Error(w, "Error creating proxy request", http.StatusInternalServerError)
3030
}
3131

@@ -38,7 +38,7 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
3838

3939
requestBody, err := io.ReadAll(proxyReq.Body)
4040
if err != nil {
41-
log.Println(err)
41+
fmt.Println(err)
4242
http.Error(w, "error reading request body", http.StatusInternalServerError)
4343
}
4444

@@ -49,17 +49,17 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
4949

5050
astQuery, err := graphcache.GetASTFromQuery(request.Query)
5151
if err != nil {
52-
log.Println(err)
52+
fmt.Println(err)
5353
http.Error(w, "error parsing query", http.StatusInternalServerError)
5454
}
5555

5656
transformedBody, err := graphcache.AddTypenameToQuery(request.Query)
5757
if err != nil {
58-
log.Println(err)
58+
fmt.Println(err)
5959
http.Error(w, "error transforming body", http.StatusInternalServerError)
6060
}
6161

62-
log.Println("time taken to transform body ", time.Since(start))
62+
fmt.Println("time taken to transform body ", time.Since(start))
6363

6464
transformedRequest := request
6565
transformedRequest.Query = transformedBody
@@ -89,30 +89,28 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
8989
// Set the status code of the original response to the status code of the proxy response
9090
w.WriteHeader(resp.StatusCode)
9191

92-
// Copy the body of the proxy response to the original response
93-
io.Copy(w, resp.Body)
94-
9592
responseBody := new(bytes.Buffer)
9693
io.Copy(responseBody, resp.Body)
9794

9895
responseMap := make(map[string]interface{})
9996
err = json.Unmarshal(responseBody.Bytes(), &responseMap)
10097
if err != nil {
101-
log.Println("Error unmarshalling response:", err, string(responseBody.Bytes()))
98+
fmt.Println("Error unmarshalling response:", string(responseBody.Bytes()))
10299
}
103100

104101
cache.InvalidateCache("data", responseMap, nil)
102+
w.Write(responseBody.Bytes())
105103
return
106104
}
107105

108106
cachedResponse, err := cache.ParseASTBuildResponse(astQuery, request)
109107
if err == nil && cachedResponse != nil {
110-
log.Println("serving response from cache...")
108+
fmt.Println("serving response from cache...")
111109
br, err := json.Marshal(cachedResponse)
112110
if err != nil {
113111
http.Error(w, "error marshalling response", http.StatusInternalServerError)
114112
}
115-
log.Println("time taken to serve response from cache ", time.Since(start))
113+
fmt.Println("time taken to serve response from cache ", time.Since(start))
116114
graphqlresponse := graphcache.GraphQLResponse{Data: json.RawMessage(br)}
117115
res, err := cache.RemoveTypenameFromResponse(&graphqlresponse)
118116
if err != nil {
@@ -130,15 +128,17 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
130128
// Send the proxy request using the custom transport
131129
resp, err := client.Do(proxyReq)
132130
if err != nil {
133-
log.Println(err)
131+
fmt.Println(err)
134132
http.Error(w, "error sending proxy request", http.StatusInternalServerError)
135133
}
136134
defer resp.Body.Close()
137135

138-
// Copy the headers from the proxy response to the original response
136+
// copy the headers from the proxy response to the original response
139137
for name, values := range resp.Header {
140-
for _, value := range values {
141-
w.Header().Add(name, value)
138+
if name != "Content-Length" { // copy all headers except Content-Length
139+
for _, value := range values {
140+
w.Header().Add(name, value)
141+
}
142142
}
143143
}
144144

@@ -148,18 +148,18 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
148148
responseMap := make(map[string]interface{})
149149
err = json.Unmarshal(responseBody.Bytes(), &responseMap)
150150
if err != nil {
151-
log.Println("Error unmarshalling response:", err, string(responseBody.Bytes()))
151+
fmt.Println("Error unmarshalling response:", string(responseBody.Bytes()))
152152
}
153153

154-
log.Println("time taken to get response from API ", time.Since(start))
154+
fmt.Println("time taken to get response from API ", time.Since(start))
155155

156156
astWithTypes, err := graphcache.GetASTFromQuery(transformedRequest.Query)
157157
if err != nil {
158-
log.Println(err)
158+
fmt.Println(err)
159159
http.Error(w, "error parsing query", http.StatusInternalServerError)
160160
}
161161

162-
log.Println("time taken to generate AST with types ", time.Since(start))
162+
fmt.Println("time taken to generate AST with types ", time.Since(start))
163163

164164
reqVariables := transformedRequest.Variables
165165
variables := make(map[string]interface{})
@@ -177,7 +177,7 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
177177
}
178178
}
179179

180-
log.Println("time taken to build response key ", time.Since(start))
180+
fmt.Println("time taken to build response key ", time.Since(start))
181181

182182
// go through the response. Every object that has a __typename field, and an id field cache it in the format of typename:id
183183
// for example, if the response has an object with __typename: "Organisation" and id: "1234", cache it as Organisation:1234
@@ -186,23 +186,15 @@ func GetCacheHandler(cache *graphcache.GraphCache, cfg *config.Config) http.Hand
186186

187187
cache.CacheResponse("data", responseMap, nil)
188188

189-
log.Println("time taken to cache response ", time.Since(start))
190-
191-
// Copy the body of the proxy response to the original response
192-
// io.Copy(w, resp.Body)
193-
194-
resBody, err := io.ReadAll(resp.Body)
195-
if err != nil {
196-
http.Error(w, "error reading response body", http.StatusInternalServerError)
197-
}
189+
fmt.Println("time taken to cache response ", time.Since(start), responseMap)
198190

199191
newResponse := &graphcache.GraphQLResponse{}
200-
newResponse.FromBytes(resBody)
192+
newResponse.FromBytes(responseBody.Bytes())
201193
res, err := cache.RemoveTypenameFromResponse(newResponse)
202194
if err != nil {
203195
http.Error(w, "error removing __typename", http.StatusInternalServerError)
204196
}
205197
w.Write(res.Bytes())
206-
// w.WriteHeader(http.StatusOK)
198+
w.Header().Add("graphql_cache", "miss")
207199
})
208200
}

api/handlers/debug_handlers.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
package handlers
22

33
import (
4+
"encoding/json"
45
"graphql_cache/config"
56
"graphql_cache/graphcache"
67
"net/http"
78
)
89

910
func GetDebugHandler(Cache *graphcache.GraphCache, cfg *config.Config) http.HandlerFunc {
1011
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11-
Cache.Debug()
12+
resp := Cache.Look()
13+
br, err := json.Marshal(resp)
14+
if err != nil {
15+
http.Error(w, "error marshalling response", http.StatusInternalServerError)
16+
}
1217
w.WriteHeader(http.StatusOK)
13-
w.Write([]byte("success"))
18+
w.Write(br)
1419
})
1520
}

api/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type Server struct {
1515
}
1616

1717
func NewGraphCache(cfg *config.Config) *graphcache.GraphCache {
18-
return graphcache.NewGraphCache(cfg.CacheBackend)
18+
return graphcache.NewGraphCache(cfg)
1919
}
2020

2121
func NewServer(cfg *config.Config) *Server {

cache/inmemory_cache.go

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,54 @@ package cache
22

33
import (
44
"encoding/json"
5+
"errors"
56
"graphql_cache/utils/file_utils"
7+
"strings"
68
)
79

8-
// InMemoryCache implements the Cache interface and uses an in-memory map as the cache store
910
type InMemoryCache struct {
10-
cache map[string]interface{}
11+
data map[string]interface{}
1112
}
1213

1314
func NewInMemoryCache() *InMemoryCache {
1415
return &InMemoryCache{
15-
cache: make(map[string]interface{}),
16+
data: make(map[string]interface{}),
1617
}
1718
}
1819

1920
func (c *InMemoryCache) Set(key string, value interface{}) error {
20-
c.cache[key] = value
21+
c.data[key] = deepCopy(value)
2122
return nil
2223
}
2324

2425
func (c *InMemoryCache) Get(key string) (interface{}, error) {
25-
return c.cache[key], nil
26+
value, exists := c.data[key]
27+
if !exists {
28+
return nil, errors.New("key not found")
29+
}
30+
return deepCopy(value), nil
2631
}
2732

2833
func (c *InMemoryCache) Del(key string) error {
29-
delete(c.cache, key)
34+
c.Set(key, nil)
3035
return nil
3136
}
3237

3338
func (c *InMemoryCache) Exists(key string) (bool, error) {
34-
_, exists := c.cache[key]
39+
_, exists := c.data[key]
3540
return exists, nil
3641
}
3742

3843
func (c *InMemoryCache) Map() (map[string]interface{}, error) {
39-
return c.cache, nil
44+
copy := make(map[string]interface{})
45+
for k, v := range c.data {
46+
copy[k] = v
47+
}
48+
return copy, nil
4049
}
4150

4251
func (c *InMemoryCache) JSON() ([]byte, error) {
43-
return json.Marshal(c.cache)
52+
return json.Marshal(c.data)
4453
}
4554

4655
func (c *InMemoryCache) Debug(identifier string) error {
@@ -52,15 +61,38 @@ func (c *InMemoryCache) Debug(identifier string) error {
5261
}
5362

5463
func (c *InMemoryCache) Flush() error {
55-
c.cache = make(map[string]interface{})
64+
c.data = make(map[string]interface{})
5665
return nil
5766
}
5867

5968
func (c *InMemoryCache) DeleteByPrefix(prefix string) error {
60-
for key := range c.cache {
61-
if len(key) >= len(prefix) && key[:len(prefix)] == prefix {
62-
delete(c.cache, key)
69+
for k := range c.data {
70+
if strings.HasPrefix(k, prefix) {
71+
c.Del(k)
6372
}
6473
}
6574
return nil
6675
}
76+
77+
func deepCopy(v interface{}) interface{} {
78+
if v == nil {
79+
return nil
80+
}
81+
82+
switch val := v.(type) {
83+
case map[string]interface{}:
84+
newMap := make(map[string]interface{})
85+
for k, v := range val {
86+
newMap[k] = deepCopy(v)
87+
}
88+
return newMap
89+
case []interface{}:
90+
newSlice := make([]interface{}, len(val))
91+
for i, v := range val {
92+
newSlice[i] = deepCopy(v)
93+
}
94+
return newSlice
95+
default:
96+
return v
97+
}
98+
}

cache/redis_cache.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ type RedisCache struct {
1515
cache *redis.Client
1616
}
1717

18-
func NewRedisCache() Cache {
18+
func NewRedisCache(host, port string) Cache {
1919
c := redis.NewClient(&redis.Options{
20-
Addr: "localhost:6379",
20+
Addr: host + ":" + port,
2121
Password: "", // no password set
2222
DB: 0, // use default DB
2323
})

config.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# If your cache is running on https://api.acme.com/api/graphql then you should set the following:
44
# origin="https://api.acme.com/api/graphql"
55

6-
origin="http://localhost:8080"
6+
origin="http://localhost:8080/graphql"
77

88

99
# Next, we need to configure the port that our cache will run on.
@@ -17,7 +17,11 @@ port=9090
1717
# redis
1818
# in_memory
1919

20-
cache_backend="redis"
20+
cache_backend="in_memory"
21+
22+
[redis]
23+
host="localhost"
24+
port=6379
2125

2226

2327
# If you want to override the API paths for the cache server, you can configure them here.

config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ type Config struct {
1919
DebugPath string `toml:"debug_path"`
2020
HealthPath string `toml:"health_path"`
2121
} `toml:"handlers"`
22+
Redis struct {
23+
Host string `toml:"host"`
24+
Port int `toml:"port"`
25+
} `toml:"redis"`
2226
}
2327

2428
const CONFIG_FILE = "./config.toml"
@@ -75,5 +79,6 @@ func NewConfig() *Config {
7579
Port: cfg.Port,
7680
CacheBackend: cfg.CacheBackend,
7781
Handlers: cfg.Handlers,
82+
Redis: cfg.Redis,
7883
}
7984
}

0 commit comments

Comments
 (0)