This commit is contained in:
Bel LaPointe
2024-02-20 08:23:37 -07:00
parent 4241b83721
commit a1d9e30030
2 changed files with 85 additions and 10 deletions

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"embed" "embed"
"encoding/base64" "encoding/base64"
"encoding/json"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@@ -12,6 +13,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"path"
"strings" "strings"
"syscall" "syscall"
@@ -21,11 +23,30 @@ import (
type Config struct { type Config struct {
Addr string Addr string
RPS int RPS int
fsDB string
} }
type Handler struct { type Handler struct {
cfg Config cfg Config
limiter *rate.Limiter limiter *rate.Limiter
db DB
}
type DB interface {
GetQuestion(string) (Question, error)
PutAnswer(string, Answer) error
GetAnswers(string) ([]Answer, error)
}
type fsDB string
type Question struct {
Text string
Options []string
}
type Answer struct {
Text string
} }
type Session struct { type Session struct {
@@ -66,6 +87,7 @@ func (cfg Config) NewHandler() Handler {
return Handler{ return Handler{
cfg: cfg, cfg: cfg,
limiter: rate.NewLimiter(rate.Limit(cfg.RPS), 10), limiter: rate.NewLimiter(rate.Limit(cfg.RPS), 10),
db: fsDB(cfg.fsDB),
} }
} }
@@ -138,20 +160,58 @@ func (h Handler) handle(session Session, w http.ResponseWriter, r *http.Request)
http.FileServer(public).ServeHTTP(w, r) http.FileServer(public).ServeHTTP(w, r)
return nil return nil
} }
switch r.URL.Path { if strings.HasPrefix(r.URL.Path, "/api/v1/questions/") {
case "/api/v1/question":
return h.handleAPIV1Question(session, w, r) return h.handleAPIV1Question(session, w, r)
case "/api/v1/answer": }
return h.handleAPIV1Answer(session, w, r) if strings.HasPrefix(r.URL.Path, "/api/v1/questions") {
return h.handleAPIV1Questions(session, w, r)
}
if strings.HasPrefix(r.URL.Path, "/api/v1/answers") {
return h.handleAPIV1Answers(session, w, r)
} }
http.NotFound(w, r) http.NotFound(w, r)
return nil return nil
} }
func (h Handler) handleAPIV1Question(session Session, w http.ResponseWriter, r *http.Request) error { func (h Handler) handleAPIV1Question(session Session, w http.ResponseWriter, r *http.Request) error {
id := path.Base(r.URL.Path)
q, err := h.db.GetQuestion(id)
if err != nil {
return err
}
return json.NewEncoder(w).Encode(q)
}
func (h Handler) handleAPIV1Questions(session Session, w http.ResponseWriter, r *http.Request) error {
return errors.New("not impl") return errors.New("not impl")
} }
func (h Handler) handleAPIV1Answer(session Session, w http.ResponseWriter, r *http.Request) error { func (h Handler) handleAPIV1Answers(session Session, w http.ResponseWriter, r *http.Request) error {
return errors.New("not impl") return errors.New("not impl")
} }
func (db fsDB) GetQuestion(id string) (Question, error) {
p := db.path(id)
b, err := os.ReadFile(p)
if err != nil {
return Question{}, err
}
var q Question
if err := json.Unmarshal(b, &q); err != nil {
return Question{}, err
}
return q, nil
}
func (db fsDB) PutAnswer(id string, a Answer) error {
return errors.New("not impl")
}
func (db fsDB) GetAnswers(id string) ([]Answer, error) {
return nil, errors.New("not impl")
}
func (db fsDB) path(q string) string {
return path.Join(string(db), q)
}

View File

@@ -8,7 +8,9 @@ import (
) )
func TestRunHTTP(t *testing.T) { func TestRunHTTP(t *testing.T) {
cfg := Config{} cfg := Config{
fsDB: t.TempDir(),
}
h := cfg.NewHandler() h := cfg.NewHandler()
@@ -53,8 +55,8 @@ func TestRunHTTP(t *testing.T) {
} }
}) })
t.Run("/api/v1/question", func(t *testing.T) { t.Run("/api/v1/questions/0", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/v1/question", nil) r := httptest.NewRequest(http.MethodGet, "/api/v1/questions/0", nil)
r.SetBasicAuth("b", "b") r.SetBasicAuth("b", "b")
w := httptest.NewRecorder() w := httptest.NewRecorder()
t.Logf("%s %s", r.Method, r.URL) t.Logf("%s %s", r.Method, r.URL)
@@ -66,8 +68,21 @@ func TestRunHTTP(t *testing.T) {
t.Errorf("not impl: %s", w.Body.Bytes()) t.Errorf("not impl: %s", w.Body.Bytes())
}) })
t.Run("/api/v1/answer", func(t *testing.T) { t.Run("/api/v1/questions", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/v1/answer", nil) r := httptest.NewRequest(http.MethodGet, "/api/v1/questions", nil)
r.SetBasicAuth("b", "b")
w := httptest.NewRecorder()
t.Logf("%s %s", r.Method, r.URL)
h.ServeHTTP(w, r)
t.Logf("(%d) %s", w.Code, w.Body.Bytes())
if w.Code != http.StatusNotFound {
t.Error(w.Code)
}
t.Errorf("not impl: %s", w.Body.Bytes())
})
t.Run("/api/v1/answers", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/v1/answers", nil)
r.SetBasicAuth("b", "b") r.SetBasicAuth("b", "b")
w := httptest.NewRecorder() w := httptest.NewRecorder()
t.Logf("%s %s", r.Method, r.URL) t.Logf("%s %s", r.Method, r.URL)