github.com/blong14/gache@v0.0.0-20240124023949-89416fd8bbfa/internal/server/handlers.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"io"
     7  	"log"
     8  	"net/http"
     9  
    10  	gdb "github.com/blong14/gache/internal/db"
    11  	ghttp "github.com/blong14/gache/internal/io/http"
    12  	gproxy "github.com/blong14/gache/internal/proxy"
    13  )
    14  
    15  type ErrorResponse struct {
    16  	Error string `json:"error"`
    17  }
    18  
    19  func HealthzService(w http.ResponseWriter, _ *http.Request) {
    20  	if _, err := io.WriteString(w, "ok"); err != nil {
    21  		log.Println(err)
    22  	}
    23  }
    24  
    25  type GetValueResponse struct {
    26  	Status string `json:"status"`
    27  	Key    string `json:"key"`
    28  	Value  string `json:"value"`
    29  }
    30  
    31  func getValueService(proxy *gproxy.QueryProxy) http.HandlerFunc {
    32  	return func(w http.ResponseWriter, r *http.Request) {
    33  		urlQuery := r.URL.Query()
    34  		if !urlQuery.Has("key") {
    35  			err := ErrorResponse{Error: "missing key"}
    36  			ghttp.MustWriteJSON(w, r, http.StatusBadRequest, err)
    37  			return
    38  		}
    39  		key := urlQuery.Get("key")
    40  		table := urlQuery.Get("table")
    41  		if table == "" {
    42  			table = "default"
    43  		}
    44  		ctx, cancel := context.WithCancel(r.Context())
    45  		defer cancel()
    46  		query, _ := gdb.NewGetValueQuery(ctx, []byte(table), []byte(key))
    47  		proxy.Send(ctx, query)
    48  		result := query.GetResponse()
    49  		var resp GetValueResponse
    50  		var status int
    51  		switch {
    52  		case !result.Success:
    53  			status = http.StatusNotFound
    54  			resp.Status = "not found"
    55  			resp.Key = key
    56  		default:
    57  			status = http.StatusOK
    58  			resp.Status = "ok"
    59  			resp.Key = key
    60  			resp.Value = string(result.Value)
    61  		}
    62  		ghttp.MustWriteJSON(w, r, status, resp)
    63  	}
    64  }
    65  
    66  type SetValueRequest struct {
    67  	Table string `json:"table"`
    68  	Key   string `json:"key"`
    69  	Value string `json:"value"`
    70  }
    71  
    72  type SetValueResponse struct {
    73  	Status string `json:"status"`
    74  	Key    string `json:"key"`
    75  	Value  string `json:"value"`
    76  }
    77  
    78  func setValueService(proxy *gproxy.QueryProxy) http.HandlerFunc {
    79  	return func(w http.ResponseWriter, r *http.Request) {
    80  		body := r.Body
    81  		if body == nil {
    82  			resp := ErrorResponse{Error: "server error"}
    83  			ghttp.MustWriteJSON(w, r, http.StatusInternalServerError, resp)
    84  			return
    85  		}
    86  		defer func() { _ = body.Close() }()
    87  		decoder := json.NewDecoder(body)
    88  		var req SetValueRequest
    89  		if err := decoder.Decode(&req); err != nil {
    90  			resp := ErrorResponse{Error: err.Error()}
    91  			ghttp.MustWriteJSON(w, r, http.StatusUnprocessableEntity, resp)
    92  			return
    93  		}
    94  		ctx, cancel := context.WithCancel(r.Context())
    95  		defer cancel()
    96  		query, _ := gdb.NewSetValueQuery(ctx, []byte(req.Table), []byte(req.Key), []byte(req.Value))
    97  		proxy.Send(ctx, query)
    98  		result := query.GetResponse()
    99  		var resp SetValueResponse
   100  		var status int
   101  		switch {
   102  		case !result.Success:
   103  			status = http.StatusNotFound
   104  			resp.Status = "not found"
   105  			resp.Key = req.Key
   106  		default:
   107  			status = http.StatusCreated
   108  			resp.Status = "created"
   109  			resp.Key = req.Key
   110  			resp.Value = string(result.Value)
   111  		}
   112  		ghttp.MustWriteJSON(w, r, status, resp)
   113  	}
   114  }
   115  
   116  func HTTPHandlers(proxy *gproxy.QueryProxy) ghttp.Handler {
   117  	return map[string]http.HandlerFunc{
   118  		"/healthz": HealthzService,
   119  		"/get":     MustBe(http.MethodGet, getValueService(proxy)),
   120  		"/set":     MustBe(http.MethodPost, setValueService(proxy)),
   121  	}
   122  }