main
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"
"embed"
"encoding/base64"
"encoding/json"
"errors"
"flag"
"fmt"
@ -12,6 +13,7 @@ import (
"net/http"
"os"
"os/signal"
"path"
"strings"
"syscall"
@ -21,11 +23,30 @@ import (
type Config struct {
Addr string
RPS int
fsDB string
}
type Handler struct {
cfg Config
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 {
@ -66,6 +87,7 @@ func (cfg Config) NewHandler() Handler {
return Handler{
cfg: cfg,
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)
return nil
}
switch r.URL.Path {
case "/api/v1/question":
if strings.HasPrefix(r.URL.Path, "/api/v1/questions/") {
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)
return nil
}
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")
}
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")
}
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) {
cfg := Config{}
cfg := Config{
fsDB: t.TempDir(),
}
h := cfg.NewHandler()
@ -53,8 +55,8 @@ func TestRunHTTP(t *testing.T) {
}
})
t.Run("/api/v1/question", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/v1/question", nil)
t.Run("/api/v1/questions/0", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/v1/questions/0", nil)
r.SetBasicAuth("b", "b")
w := httptest.NewRecorder()
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.Run("/api/v1/answer", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/v1/answer", nil)
t.Run("/api/v1/questions", func(t *testing.T) {
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")
w := httptest.NewRecorder()
t.Logf("%s %s", r.Method, r.URL)