From ea34be4e1bcaa8c3da2fa26fbe5e79383836e6a6 Mon Sep 17 00:00:00 2001 From: Annika Date: Thu, 16 Jul 2026 14:01:39 -0700 Subject: [PATCH] created dummy API routes, passing API test --- backend/database.go | 164 ++++++++++++++++++++++++++++++++++++++++ backend/main.go | 178 ++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 2 +- 3 files changed, 343 insertions(+), 1 deletion(-) diff --git a/backend/database.go b/backend/database.go index 9782806..d351a55 100644 --- a/backend/database.go +++ b/backend/database.go @@ -103,3 +103,167 @@ func createTables(db *sql.DB) error { return nil } + +// User represents a row in the users table. +type User struct { + UserID string + RootObjectID string +} + +// CreateUser inserts a new user into the users table. +func CreateUser(userID, rootObjectID string) error { + _, err := DB.Exec( + "INSERT INTO users (userId, rootObjectId) VALUES (?, ?)", + userID, rootObjectID, + ) + if err != nil { + return fmt.Errorf("failed to create user: %w", err) + } + return nil +} + +// GetUser retrieves a user by ID. +func GetUser(userID string) (User, error) { + var user User + err := DB.QueryRow( + "SELECT userId, rootObjectId FROM users WHERE userId = ?", + userID, + ).Scan(&user.UserID, &user.RootObjectID) + if err != nil { + if err == sql.ErrNoRows { + return User{}, fmt.Errorf("user not found") + } + return User{}, fmt.Errorf("failed to get user: %w", err) + } + return user, nil +} + +// UpdateUser updates the rootObjectId for a user. +func UpdateUser(userID, rootObjectID string) error { + result, err := DB.Exec( + "UPDATE users SET rootObjectId = ? WHERE userId = ?", + rootObjectID, userID, + ) + if err != nil { + return fmt.Errorf("failed to update user: %w", err) + } + rows, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to check update result: %w", err) + } + if rows == 0 { + return fmt.Errorf("user not found") + } + return nil +} + +// DeleteUser removes a user by ID. +func DeleteUser(userID string) error { + result, err := DB.Exec("DELETE FROM users WHERE userId = ?", userID) + if err != nil { + return fmt.Errorf("failed to delete user: %w", err) + } + rows, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to check delete result: %w", err) + } + if rows == 0 { + return fmt.Errorf("user not found") + } + return nil +} + +// Object represents a row in the objects table. +type Object struct { + ObjectID string + UserID string + ObjectData string +} + +// CreateObject inserts a new object into the objects table. +func CreateObject(objectID, userID, objectData string) error { + _, err := DB.Exec( + "INSERT INTO objects (objectId, userId, objectData) VALUES (?, ?, ?)", + objectID, userID, objectData, + ) + if err != nil { + return fmt.Errorf("failed to create object: %w", err) + } + return nil +} + +// GetObject retrieves an object by ID. +func GetObject(objectID string) (Object, error) { + var obj Object + err := DB.QueryRow( + "SELECT objectId, userId, objectData FROM objects WHERE objectId = ?", + objectID, + ).Scan(&obj.ObjectID, &obj.UserID, &obj.ObjectData) + if err != nil { + if err == sql.ErrNoRows { + return Object{}, fmt.Errorf("object not found") + } + return Object{}, fmt.Errorf("failed to get object: %w", err) + } + return obj, nil +} + +// GetObjectsByUser retrieves all objects belonging to a user. +func GetObjectsByUser(userID string) ([]Object, error) { + rows, err := DB.Query( + "SELECT objectId, userId, objectData FROM objects WHERE userId = ?", + userID, + ) + if err != nil { + return nil, fmt.Errorf("failed to query objects: %w", err) + } + defer rows.Close() + + var objects []Object + for rows.Next() { + var obj Object + if err := rows.Scan(&obj.ObjectID, &obj.UserID, &obj.ObjectData); err != nil { + return nil, fmt.Errorf("failed to scan object: %w", err) + } + objects = append(objects, obj) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("failed to iterate objects: %w", err) + } + return objects, nil +} + +// UpdateObject updates the objectData for an object. +func UpdateObject(objectID, objectData string) error { + result, err := DB.Exec( + "UPDATE objects SET objectData = ? WHERE objectId = ?", + objectData, objectID, + ) + if err != nil { + return fmt.Errorf("failed to update object: %w", err) + } + rows, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to check update result: %w", err) + } + if rows == 0 { + return fmt.Errorf("object not found") + } + return nil +} + +// DeleteObject removes an object by ID. +func DeleteObject(objectID string) error { + result, err := DB.Exec("DELETE FROM objects WHERE objectId = ?", objectID) + if err != nil { + return fmt.Errorf("failed to delete object: %w", err) + } + rows, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to check delete result: %w", err) + } + if rows == 0 { + return fmt.Errorf("object not found") + } + return nil +} diff --git a/backend/main.go b/backend/main.go index 90a8d5e..1b2910b 100644 --- a/backend/main.go +++ b/backend/main.go @@ -15,11 +15,13 @@ func main() { DB = db router := gin.Default() + router.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) + router.GET("/db-check", func(c *gin.Context) { if err := DB.Ping(); err != nil { c.JSON(http.StatusServiceUnavailable, gin.H{"status": "unreachable", "error": err.Error()}) @@ -27,5 +29,181 @@ func main() { } c.JSON(http.StatusOK, gin.H{"status": "ok"}) }) + + // User routes + router.POST("/users", createUserHandler) + router.GET("/users/:id", getUserHandler) + router.PUT("/users/:id", updateUserHandler) + router.DELETE("/users/:id", deleteUserHandler) + + // Object routes + router.POST("/objects", createObjectHandler) + router.GET("/objects/:id", getObjectHandler) + router.GET("/users/:id/objects", getObjectsByUserHandler) + router.PUT("/objects/:id", updateObjectHandler) + router.DELETE("/objects/:id", deleteObjectHandler) + router.Run() // listens on 0.0.0.0:8080 by default } + +// createUserRequest is the expected body for POST /users. +type createUserRequest struct { + UserID string `json:"userId" binding:"required"` + RootObjectID string `json:"rootObjectId" binding:"required"` +} + +func createUserHandler(c *gin.Context) { + var req createUserRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + if err := CreateUser(req.UserID, req.RootObjectID); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusCreated, gin.H{"status": "created"}) +} + +func getUserHandler(c *gin.Context) { + id := c.Param("id") + user, err := GetUser(id) + if err != nil { + if err.Error() == "user not found" { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, user) +} + +// updateUserRequest is the expected body for PUT /users/:id. +type updateUserRequest struct { + RootObjectID string `json:"rootObjectId" binding:"required"` +} + +func updateUserHandler(c *gin.Context) { + id := c.Param("id") + var req updateUserRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + if err := UpdateUser(id, req.RootObjectID); err != nil { + if err.Error() == "user not found" { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "updated"}) +} + +func deleteUserHandler(c *gin.Context) { + id := c.Param("id") + if err := DeleteUser(id); err != nil { + if err.Error() == "user not found" { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "deleted"}) +} + +// createObjectRequest is the expected body for POST /objects. +type createObjectRequest struct { + ObjectID string `json:"objectId" binding:"required"` + UserID string `json:"userId" binding:"required"` + ObjectData string `json:"objectData" binding:"required"` +} + +func createObjectHandler(c *gin.Context) { + var req createObjectRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + if err := CreateObject(req.ObjectID, req.UserID, req.ObjectData); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusCreated, gin.H{"status": "created"}) +} + +func getObjectHandler(c *gin.Context) { + id := c.Param("id") + obj, err := GetObject(id) + if err != nil { + if err.Error() == "object not found" { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, obj) +} + +func getObjectsByUserHandler(c *gin.Context) { + id := c.Param("id") + objects, err := GetObjectsByUser(id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, objects) +} + +// updateObjectRequest is the expected body for PUT /objects/:id. +type updateObjectRequest struct { + ObjectData string `json:"objectData" binding:"required"` +} + +func updateObjectHandler(c *gin.Context) { + id := c.Param("id") + var req updateObjectRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + if err := UpdateObject(id, req.ObjectData); err != nil { + if err.Error() == "object not found" { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "updated"}) +} + +func deleteObjectHandler(c *gin.Context) { + id := c.Param("id") + if err := DeleteObject(id); err != nil { + if err.Error() == "object not found" { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "deleted"}) +} diff --git a/docker-compose.yml b/docker-compose.yml index 35c567d..8813b52 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ services: - application: + backend: build: ./backend container_name: ${SERVICE_NAME}-oworganizer-backend environment: