diff --git a/server/api/api.go b/server/api/api.go index 0b8df80..e61aef9 100644 --- a/server/api/api.go +++ b/server/api/api.go @@ -25,6 +25,9 @@ func Start() { r.Route("/users", func(r chi.Router) { r.Get("/", ListUsers) + r.Route("/{userID}", func(r chi.Router) { + r.Get("/", GetUser) + }) }) r.Route("/register", func(r chi.Router) { diff --git a/server/api/db.go b/server/api/db.go index 84a120e..11bf2e2 100644 --- a/server/api/db.go +++ b/server/api/db.go @@ -10,13 +10,15 @@ import ( "github.com/jackc/pgx/v5" ) +var ErrUserNotFound = errors.New("db: user not found") + func dbGetUser(id string) (*User, error) { query := `SELECT id, name, password FROM users WHERE id = $1` var user User err := db.Pool.QueryRow(context.Background(), query, id).Scan(&user.ID, &user.Name, &user.Password) if errors.Is(err, pgx.ErrNoRows) { slog.Debug("db: user not found", "userid", id) - return nil, errors.New("user not found") + return nil, ErrUserNotFound } else if err != nil { slog.Error("db: failed to query user", "error", err) return nil, fmt.Errorf("failed to query user") @@ -32,7 +34,7 @@ func dbGetUserByName(username string) (*User, error) { err := db.Pool.QueryRow(context.Background(), query, username).Scan(&user.ID, &user.Name, &user.Password) if errors.Is(err, pgx.ErrNoRows) { slog.Debug("db: user not found", "username", username) - return nil, errors.New("user not found") + return nil, ErrUserNotFound } else if err != nil { slog.Error("db: failed to query user", "error", err) return nil, fmt.Errorf("failed to query user") diff --git a/server/api/user.go b/server/api/user.go index 8e0e55b..c1d2cef 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -1,9 +1,11 @@ package api import ( + "errors" "log/slog" "net/http" + "github.com/go-chi/chi/v5" "github.com/go-chi/render" "github.com/google/uuid" ) @@ -35,6 +37,34 @@ func ListUsers(w http.ResponseWriter, r *http.Request) { } } +func GetUser(w http.ResponseWriter, r *http.Request) { + slog.Debug("user: entering GetUser handler") + + userID := chi.URLParam(r, "userID") + parsed, err := uuid.Parse(userID) + if err != nil { + render.Render(w, r, ErrInvalidRequest(err)) + return + } + + user, err := dbGetUser(parsed.String()) + if err != nil { + if errors.Is(err, ErrUserNotFound) { + render.Render(w, r, ErrNotFound) + } else { + slog.Error("user: failed to fetch user", "userid", parsed.String(), "error", err) + render.Render(w, r, ErrRender(err)) + } + return + } + + slog.Debug("user: rendering user", "userid", user.ID, "username", user.Name) + if err := render.Render(w, r, NewUserPayloadResponse(user)); err != nil { + slog.Error("user: failed to render user", "userid", parsed.String(), "error", err) + render.Render(w, r, ErrRender(err)) + } +} + func newUserID() uuid.UUID { return uuid.New() }