diff --git a/cmd/api/handlers.go b/cmd/api/handlers.go new file mode 100644 index 0000000..046c42e --- /dev/null +++ b/cmd/api/handlers.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "net/http" +) + +func (app *application) createMovieHandler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusAccepted) + fmt.Fprintln(w, "Resource created") +} + +func (app *application) getAllMoviesHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "Movies List") +} + +func (app *application) healthCheckHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "status: available!") + fmt.Fprintf(w, "environment: %s\n", app.config.env) + fmt.Fprintf(w, "version: %s\n", Version) +} diff --git a/cmd/api/handlers_test.go b/cmd/api/handlers_test.go new file mode 100644 index 0000000..3062039 --- /dev/null +++ b/cmd/api/handlers_test.go @@ -0,0 +1,109 @@ +package main + +import ( + "bytes" + "io" + "log/slog" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func newTestApplication() application { + cfg := config{env: "test"} + return application{config: cfg, logger: slog.New(slog.NewTextHandler(io.Discard, nil))} + +} + +func TestHealthRoute(t *testing.T) { + respRec := httptest.NewRecorder() + + r, err := http.NewRequest(http.MethodGet, "/v1/healthcheck", nil) + if err != nil { + t.Fatal(err) + } + + app := newTestApplication() + health := http.HandlerFunc(app.healthCheckHandler) + health.ServeHTTP(respRec, r) + + resp := respRec.Result() + + if resp.StatusCode != http.StatusOK { + t.Fatalf("Got status code %q, wanted status code %q", resp.StatusCode, http.StatusOK) + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + body = bytes.TrimSpace(body) + + if !strings.Contains(string(body), "environment: test") { + t.Fatalf("Did not find: %q in response body", "environment: test") + } +} + +func TestCreateMovieHandler(t *testing.T) { + respRec := httptest.NewRecorder() + want := "Resource created" + + r, err := http.NewRequest(http.MethodPost, "/v1/movies", nil) + if err != nil { + t.Fatal(err) + } + + app := newTestApplication() + movie := http.HandlerFunc(app.createMovieHandler) + movie.ServeHTTP(respRec, r) + + resp := respRec.Result() + + if resp.StatusCode != http.StatusAccepted { + t.Fatalf("Got status code %q, wanted status code %q", resp.StatusCode, http.StatusOK) + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + body = bytes.TrimSpace(body) + + if !strings.Contains(string(body), want) { + t.Fatalf("Did not find: %q in response body", want) + } +} + +func TestGetAllMoviesHandler(t *testing.T) { + respRec := httptest.NewRecorder() + want := "Movies List" + + r, err := http.NewRequest(http.MethodGet, "/v1/movies", nil) + if err != nil { + t.Fatal(err) + } + + app := newTestApplication() + movie := http.HandlerFunc(app.getAllMoviesHandler) + movie.ServeHTTP(respRec, r) + + resp := respRec.Result() + + if resp.StatusCode != http.StatusOK { + t.Fatalf("Got status code %q, wanted status code %q", resp.StatusCode, http.StatusOK) + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + body = bytes.TrimSpace(body) + + if !strings.Contains(string(body), want) { + t.Fatalf("Did not find: %q in response body", want) + } +} diff --git a/cmd/api/healthcheck.go b/cmd/api/healthcheck.go deleted file mode 100644 index 275eb1c..0000000 --- a/cmd/api/healthcheck.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "fmt" - "net/http" -) - -func (app *application) HealthCheckHandler(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "status: available!") - fmt.Fprintf(w, "environment: %s\n", app.config.env) - fmt.Fprintf(w, "version: %s\n", Version) -} diff --git a/cmd/api/healthcheck_test.go b/cmd/api/healthcheck_test.go deleted file mode 100644 index 252b406..0000000 --- a/cmd/api/healthcheck_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "bytes" - "io" - "log/slog" - "net/http" - "net/http/httptest" - "strings" - "testing" -) - -func TestHealthRoute(t *testing.T) { - respRec := httptest.NewRecorder() - - r, err := http.NewRequest(http.MethodGet, "/v1/healthcheck", nil) - if err != nil { - t.Fatal(err) - } - cfg := config{env: "test"} - - app := application{config: cfg, logger: slog.New(slog.NewTextHandler(io.Discard, nil))} - - health := http.HandlerFunc(app.HealthCheckHandler) - health.ServeHTTP(respRec, r) - - resp := respRec.Result() - - if resp.StatusCode != http.StatusOK { - t.Fatalf("Got status code %q, wanted status code %q", resp.StatusCode, http.StatusOK) - } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - - body = bytes.TrimSpace(body) - - if !strings.Contains(string(body), "environment: test") { - t.Fatalf("Did not find: %q in response body", "environment: test") - } -} diff --git a/cmd/api/main.go b/cmd/api/main.go index 4be16fc..f7cf781 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -45,9 +45,6 @@ func run(ctx context.Context, w io.Writer, args []string) error { logger := logging.InitLogging(cfg.logLevel, w, true) app := application{config: cfg, logger: logger} - mux := http.NewServeMux() - mux.HandleFunc("/v1/healthcheck", app.HealthCheckHandler) - srv := &http.Server{ Addr: fmt.Sprintf("%s:%d", "0.0.0.0", app.config.port), ErrorLog: slog.NewLogLogger(app.logger.Handler(), slog.LevelError), @@ -55,7 +52,7 @@ func run(ctx context.Context, w io.Writer, args []string) error { ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 524288, // 0.5 mb - Handler: mux, + Handler: app.routes(), } slog.Info(fmt.Sprintf("Listening on http://%s", srv.Addr)) diff --git a/cmd/api/routes.go b/cmd/api/routes.go new file mode 100644 index 0000000..1798140 --- /dev/null +++ b/cmd/api/routes.go @@ -0,0 +1,17 @@ +package main + +import ( + "net/http" + + "github.com/julienschmidt/httprouter" +) + +func (app *application) routes() http.Handler { + router := httprouter.New() + + router.HandlerFunc(http.MethodGet, "/v1/healthcheck", app.healthCheckHandler) + router.HandlerFunc(http.MethodPost, "/v1/movies", app.createMovieHandler) + router.HandlerFunc(http.MethodGet, "/v1/movies", app.getAllMoviesHandler) + + return router +} diff --git a/go.mod b/go.mod index b19f022..5d5ad0b 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,6 @@ module git.runcible.io/learning/pulley //go 1.24.1 -go 1.23.3 \ No newline at end of file +go 1.23.3 + +require github.com/julienschmidt/httprouter v1.3.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..096c54e --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=