From 52317a8c4bb8716468a1fdd669163fcbb8c2b96d Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen Date: Thu, 8 May 2025 11:29:55 +0200 Subject: [PATCH] Add /user/{userId} --- backend/api_test.go | 23 ++++++++++++++++++++--- backend/db.go | 15 +++++++++++++++ backend/go.mod | 2 +- backend/go.sum | 4 ++-- backend/main.go | 34 ++++++++++++++++++++++++++++++---- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/backend/api_test.go b/backend/api_test.go index 40aab9c..597d14c 100644 --- a/backend/api_test.go +++ b/backend/api_test.go @@ -5,7 +5,7 @@ import ( ) import "github.com/gavv/httpexpect/v2" -func startServer(t *testing.T) { +func startServer(t *testing.T) *httpexpect.Expect { config := ServerConfig{ Datasource: ":memory:", Port: "8181", @@ -13,13 +13,30 @@ func startServer(t *testing.T) { } go start(t.Context(), &config) <-config.Started + return httpexpect.Default(t, "http://localhost:8181/api") } func TestGetUsers(t *testing.T) { - startServer(t) - e := httpexpect.Default(t, "http://localhost:8181/api") + e := startServer(t) result := e.GET("/users").Expect().Status(200).JSON() result.Array().Length().IsEqual(2) result.Path("$[0].name").InList("Seeseemelk", "Huffle") result.Path("$[1].name").InList("Seeseemelk", "Huffle") } + +func TestGetUser(t *testing.T) { + e := startServer(t) + result := e.GET("/user/1").Expect().Status(200).JSON().Object() + result.Value("name").IsEqual("Seeseemelk") + result.Value("id").IsEqual(1) +} + +func TestGetUserUnknown(t *testing.T) { + e := startServer(t) + e.GET("/user/999").Expect().Status(404) +} + +func TestGetUserBadId(t *testing.T) { + e := startServer(t) + e.GET("/user/bad-id").Expect().Status(400) +} diff --git a/backend/db.go b/backend/db.go index 98ead12..b479b8a 100644 --- a/backend/db.go +++ b/backend/db.go @@ -1,6 +1,7 @@ package main import ( + "errors" "gitea.seeseepuff.be/seeseemelk/mysqlite" "log" ) @@ -42,3 +43,17 @@ func (db *Db) GetUsers() ([]User, error) { } return users, nil } + +func (db *Db) GetUser(id int) (*User, error) { + user := &User{} + + err := db.db.Query("select id, name from users where id = ?"). + Bind(id).ScanSingle(&user.ID, &user.Name) + if errors.Is(err, mysqlite.ErrNoRows) { + return nil, nil + } + if err != nil { + return nil, err + } + return user, nil +} diff --git a/backend/go.mod b/backend/go.mod index fadfbae..55f7dee 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -3,7 +3,7 @@ module allowance_planner go 1.24.2 require ( - gitea.seeseepuff.be/seeseemelk/mysqlite v0.9.0 + gitea.seeseepuff.be/seeseemelk/mysqlite v0.10.0 github.com/gavv/httpexpect/v2 v2.17.0 github.com/gin-gonic/gin v1.10.0 ) diff --git a/backend/go.sum b/backend/go.sum index 52f8d93..8942a76 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,5 +1,5 @@ -gitea.seeseepuff.be/seeseemelk/mysqlite v0.9.0 h1:GaU2DSrgDfZEqST3HdnNgfKSI4sNXvMm8SSfeMvBxA4= -gitea.seeseepuff.be/seeseemelk/mysqlite v0.9.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE= +gitea.seeseepuff.be/seeseemelk/mysqlite v0.10.0 h1:xvbSZvLcHWlt+P4SE7vcgw3kih0kLrCqkOo/eXlbcSg= +gitea.seeseepuff.be/seeseemelk/mysqlite v0.10.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= diff --git a/backend/main.go b/backend/main.go index 4c3454e..295e717 100644 --- a/backend/main.go +++ b/backend/main.go @@ -8,6 +8,7 @@ import ( "log" "net/http" "os" + "strconv" ) //go:embed migrations/*.sql @@ -30,18 +31,36 @@ func getUsers(c *gin.Context) { c.IndentedJSON(http.StatusOK, users) } -func main() { - config := ServerConfig{ - Datasource: os.Getenv("DB_PATH"), +func getUser(c *gin.Context) { + userIdStr := c.Param("userId") + userId, err := strconv.Atoi(userIdStr) + if err != nil { + log.Printf("Invalid user ID: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"}) + return } - start(context.Background(), &config) + + user, err := db.GetUser(userId) + if err != nil { + log.Printf("Error getting user: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error"}) + return + } + if user == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) + return + } + + c.IndentedJSON(http.StatusOK, user) } func start(ctx context.Context, config *ServerConfig) { db = NewDb(config.Datasource) defer db.db.MustClose() + router := gin.Default() router.GET("/api/users", getUsers) + router.GET("/api/user/:userId", getUser) srv := &http.Server{ Addr: ":" + config.Port, @@ -61,3 +80,10 @@ func start(ctx context.Context, config *ServerConfig) { log.Fatalf("Server forced to shutdown: %v", err) } } + +func main() { + config := ServerConfig{ + Datasource: os.Getenv("DB_PATH"), + } + start(context.Background(), &config) +}