http server
package main
import (
"encoding/json"
"io"
"log"
"net/http"
"sync"
)
var (
cacheObj = NewCache()
readRequestBodyError = "read body error"
unmarshalBodyError = "unmarshal body error"
marshalResultError = "unmarshal result error"
)
func NewCache() *cache {
return &cache{Data: make(map[string]struct{})}
}
type cache struct {
Data map[string]struct{}
lock sync.RWMutex
}
func (c *cache) exists(key string) bool {
c.lock.RLock()
_, ok := c.Data[key]
c.lock.RUnlock()
return ok
}
func (c *cache) set(key string) {
c.lock.Lock()
c.Data[key] = struct{}{}
c.lock.Unlock()
}
func echoHandler(writer http.ResponseWriter, request *http.Request) {
body, err := io.ReadAll(request.Body)
if err != nil {
http.Error(writer, readRequestBodyError, http.StatusInternalServerError)
return
}
var array []string
err = json.Unmarshal(body, &array)
if err != nil {
http.Error(writer, unmarshalBodyError, http.StatusInternalServerError)
return
}
result := make([]bool, len(array))
for index, value := range array {
if ok := cacheObj.exists(value); !ok {
cacheObj.set(value)
} else {
result[index] = ok
}
}
b, err := json.Marshal(result)
if err != nil {
http.Error(writer, marshalResultError, http.StatusInternalServerError)
return
}
writer.Header().Add("Content-Type", "Application/json")
writer.WriteHeader(http.StatusOK)
writer.Write(b)
}
func main() {
http.HandleFunc("/echo", echoHandler)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}
test case
package main
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestEchoServer(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(echoHandler))
defer srv.Close()
cases := []struct {
req string
exp string
}{
{req: `["a", "b", "c"]`, exp: `[false,false,false]`},
{req: `["a", "b", "c", "d"]`, exp: `[true,true,true,false]`},
{req: `["m", "d", "a"]`, exp: `[false,true,true]`},
{req: `["a", "m", "s","l"]`, exp: `[true,true,false,false]`},
}
for _, cs := range cases {
resp, err := http.Post(srv.URL, "application/json", strings.NewReader(cs.req))
if err != nil {
t.Fatalf("post error: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Errorf("reponse code error: %d", resp.StatusCode)
}
res, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("read all error: %v", err)
}
str := string(res)
if str != cs.exp {
t.Errorf("expected response body %s, but got %s", cs.exp, str)
}
}
}