Skip to content

Commit

Permalink
Merge pull request #9 from michimani/feature/8/add-handler-struct
Browse files Browse the repository at this point in the history
change handler function to method of handler struct #8
  • Loading branch information
michimani authored Jul 3, 2023
2 parents 30b716f + bc6e23c commit 232764a
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 42 deletions.
26 changes: 18 additions & 8 deletions handler/evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ import (
"github.com/michimani/evidentlylocal/types"
)

func evaluateFeature(w http.ResponseWriter, r *http.Request, l logger.Logger) {
type evaluationHandler struct {
l logger.Logger
}

func newEvaluationHandler(l logger.Logger) *evaluationHandler {
return &evaluationHandler{
l: l,
}
}

func (h *evaluationHandler) evaluateFeature(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
l.Error("Method not allowed: "+r.Method, nil)
h.l.Error("Method not allowed: "+r.Method, nil)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
Expand All @@ -25,7 +35,7 @@ func evaluateFeature(w http.ResponseWriter, r *http.Request, l logger.Logger) {
parts := strings.Split(path, "/")

if len(parts) != 5 {
l.Error("Invalid path: "+path, nil)
h.l.Error("Invalid path: "+path, nil)
http.Error(w, "Not found", http.StatusNotFound)
return
}
Expand All @@ -35,15 +45,15 @@ func evaluateFeature(w http.ResponseWriter, r *http.Request, l logger.Logger) {

feature, err := repository.FeatureRepositoryInstance().Get(project, featureName)
if err != nil {
l.Error("Failed to get feature", err)
h.l.Error("Failed to get feature", err)
http.Error(w, "Not found", http.StatusNotFound)
return
}

request := &types.EvaluateFeatureRequest{}
err = json.NewDecoder(r.Body).Decode(request)
if err != nil {
l.Error("Failed to decode request body", err)
h.l.Error("Failed to decode request body", err)
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
Expand All @@ -52,12 +62,12 @@ func evaluateFeature(w http.ResponseWriter, r *http.Request, l logger.Logger) {

reason, variation, err := components.EvaluateFeature(feature, entityID)
if err != nil {
l.Error("Failed to evaluate feature", err)
h.l.Error("Failed to evaluate feature", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}

l.Info(fmt.Sprintf("return variation: %+v", variation))
h.l.Info(fmt.Sprintf("return variation: %+v", variation))

res := types.EvaluateFeatureResponse{
Details: "{}",
Expand All @@ -75,7 +85,7 @@ func evaluateFeature(w http.ResponseWriter, r *http.Request, l logger.Logger) {
requestID := ""
uuid, err := uuid.NewV4()
if err != nil {
l.Error("Failed to generate UUID. Use constant request id.", err)
h.l.Error("Failed to generate UUID. Use constant request id.", err)
requestID = "xxxxxxxx-0000-0000-0000-xxxxxxxxxxxx"
} else {
requestID = uuid.String()
Expand Down
2 changes: 1 addition & 1 deletion handler/evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func Test_EvaluateFeature(t *testing.T) {

w := httptest.NewRecorder()

handler.Exported_evaluateFeature(w, req, testLogger)
handler.Exported_evaluateFeature(w, req)

asst.Equal(c.expectedStatus, w.Code)
asst.Equal(c.expectedBody, w.Body.String())
Expand Down
34 changes: 28 additions & 6 deletions handler/export_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package handler

import (
"net/http"
"os"
"strings"

"github.com/michimani/evidentlylocal/logger"
"github.com/michimani/evidentlylocal/repository"
)

var (
Exported_evaluateFeature = evaluateFeature
Exported_handleSomeResources = handleSomeResources
Exported_handleSpecificResource = handleSpecificResource
)

const (
dataDir = "../testdata"
)
Expand All @@ -19,3 +17,27 @@ func PrepareForTest(l logger.Logger) {
repos, _ := repository.NewFeatureRepositoryWithJSONFile(dataDir, l)
repository.SetFeatureRepositoryInstance(repos)
}

func Exported_handleSomeResources(w http.ResponseWriter, r *http.Request) {
testLogger, _ := logger.NewEvidentlyLocalLogger(os.Stdout)
ph := NewProjectHandler(testLogger)
path := r.URL.Path
parts := strings.Split(path, "/")
ph.pathParts = parts
ph.handleSomeResources(w, r)
}

func Exported_handleSpecificResource(w http.ResponseWriter, r *http.Request) {
testLogger, _ := logger.NewEvidentlyLocalLogger(os.Stdout)
ph := NewProjectHandler(testLogger)
path := r.URL.Path
parts := strings.Split(path, "/")
ph.pathParts = parts
ph.handleSpecificResource(w, r)
}

func Exported_evaluateFeature(w http.ResponseWriter, r *http.Request) {
testLogger, _ := logger.NewEvidentlyLocalLogger(os.Stdout)
eh := newEvaluationHandler(testLogger)
eh.evaluateFeature(w, r)
}
50 changes: 28 additions & 22 deletions handler/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,53 @@ package handler
import (
"fmt"
"net/http"
"os"
"strings"

"github.com/michimani/evidentlylocal/logger"
)

func Projects(w http.ResponseWriter, r *http.Request) {
l, err := logger.NewEvidentlyLocalLogger(os.Stdout)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
type ProjectHandler struct {
l logger.Logger
pathParts []string
}

func NewProjectHandler(l logger.Logger) *ProjectHandler {
return &ProjectHandler{
l: l,
}
}

func (h *ProjectHandler) Projects(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
parts := strings.Split(path, "/")
l.Info(fmt.Sprintf("%s %s", r.Method, path))
h.pathParts = parts
h.l.Info(fmt.Sprintf("%s %s", r.Method, path))

switch len(parts) {
case 2:
// GET | POST /projects
handleProjects(w, r, l)
h.handleProjects(w, r)
case 3:
// GET | PATCH | DELETE /projects/:project
handleSpecificProject(w, r, parts[2], l)
h.handleSpecificProject(w, r)
case 4:
// POST /projects/:project/evaluations
// GET | POST /projects/:project/experiments
// GET | POST /projects/:project/launches
// GET | POST /projects/:project/features
handleSomeResources(w, r, parts, l)
h.handleSomeResources(w, r)
case 5:
// POST /projects/:project/evaluations/:feature
// GET | PATCH | DELETE /projects/:project/experiments/:experiment
// GET | PATCH | DELETE /projects/:project/launches/:launch
// GET | PATCH | DELETE /projects/:project/features/:feature
handleSpecificResource(w, r, parts, l)
h.handleSpecificResource(w, r)
default:
http.Error(w, "Not found", http.StatusNotFound)
}
}

func handleProjects(w http.ResponseWriter, r *http.Request, l logger.Logger) {
func (h *ProjectHandler) handleProjects(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet, http.MethodPost:
http.Error(w, "Not implemented", http.StatusNotImplemented)
Expand All @@ -53,7 +58,7 @@ func handleProjects(w http.ResponseWriter, r *http.Request, l logger.Logger) {
}
}

func handleSpecificProject(w http.ResponseWriter, r *http.Request, project string, l logger.Logger) {
func (h *ProjectHandler) handleSpecificProject(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet, http.MethodPatch, http.MethodDelete:
http.Error(w, "Not implemented", http.StatusNotImplemented)
Expand All @@ -62,33 +67,34 @@ func handleSpecificProject(w http.ResponseWriter, r *http.Request, project strin
}
}

func handleSomeResources(w http.ResponseWriter, r *http.Request, pathPart []string, l logger.Logger) {
if len(pathPart) != 4 {
l.Error("Invalid path: "+r.URL.Path, nil)
func (h *ProjectHandler) handleSomeResources(w http.ResponseWriter, r *http.Request) {
if len(h.pathParts) != 4 {
h.l.Error("Invalid path: "+r.URL.Path, nil)
http.Error(w, "Not found", http.StatusNotFound)
return
}

switch pathPart[3] {
switch h.pathParts[3] {
case "evaluations", "experiments", "launches", "features":
http.Error(w, "Not implemented", http.StatusNotImplemented)
default:
http.Error(w, "Not found", http.StatusNotFound)
}
}

func handleSpecificResource(w http.ResponseWriter, r *http.Request, pathPart []string, l logger.Logger) {
if len(pathPart) != 5 {
l.Error("Invalid path: "+r.URL.Path, nil)
func (h *ProjectHandler) handleSpecificResource(w http.ResponseWriter, r *http.Request) {
if len(h.pathParts) != 5 {
h.l.Error("Invalid path: "+r.URL.Path, nil)
http.Error(w, "Not found", http.StatusNotFound)
return
}

switch pathPart[3] {
switch h.pathParts[3] {
case "evaluations":
// POST /projects/:project/evaluations/:feature
// https://docs.aws.amazon.com/cloudwatchevidently/latest/APIReference/API_EvaluateFeature.html
evaluateFeature(w, r, l)
eh := newEvaluationHandler(h.l)
eh.evaluateFeature(w, r)
case "experiments", "launches", "features":
http.Error(w, "Not implemented", http.StatusNotImplemented)
default:
Expand Down
8 changes: 4 additions & 4 deletions handler/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"

"github.com/michimani/evidentlylocal/handler"
Expand All @@ -16,6 +15,7 @@ import (
func Test_Project(t *testing.T) {
testLogger, _ := logger.NewEvidentlyLocalLogger(os.Stdout)
handler.PrepareForTest(testLogger)
ph := handler.NewProjectHandler(testLogger)

cases := []struct {
name string
Expand Down Expand Up @@ -595,7 +595,7 @@ func Test_Project(t *testing.T) {

w := httptest.NewRecorder()

handler.Projects(w, req)
ph.Projects(w, req)

asst.Equal(c.expectedStatus, w.Code)
asst.Equal(c.expectedBody, w.Body.String())
Expand Down Expand Up @@ -841,7 +841,7 @@ func Test_handleSomeResources(t *testing.T) {

w := httptest.NewRecorder()

handler.Exported_handleSomeResources(w, req, strings.Split(c.reqPath, "/"), testLogger)
handler.Exported_handleSomeResources(w, req)

asst.Equal(c.expectedStatus, w.Code)
asst.Equal(c.expectedBody, w.Body.String())
Expand Down Expand Up @@ -1130,7 +1130,7 @@ func Test_handleSpecificResource(t *testing.T) {

w := httptest.NewRecorder()

handler.Exported_handleSpecificResource(w, req, strings.Split(c.reqPath, "/"), testLogger)
handler.Exported_handleSpecificResource(w, req)

asst.Equal(c.expectedStatus, w.Code)
asst.Equal(c.expectedBody, w.Body.String())
Expand Down
4 changes: 3 additions & 1 deletion server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import (
func Start(port string, l logger.Logger, repoInstance repository.FeatureRepository) {
repository.SetFeatureRepositoryInstance(repoInstance)

http.HandleFunc("/projects/", handler.Projects)
ph := handler.NewProjectHandler(l)

http.HandleFunc("/projects/", ph.Projects)

l.Info(fmt.Sprintf("Server started on port %s", port))
err := http.ListenAndServe(":"+port, nil)
Expand Down

0 comments on commit 232764a

Please sign in to comment.