feat: Add REST API handlers for exercises, plans, and sessions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
166
backend/internal/api/sessions.go
Normal file
166
backend/internal/api/sessions.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"training-tracker/internal/models"
|
||||
)
|
||||
|
||||
type SessionHandler struct {
|
||||
repo SessionRepository
|
||||
}
|
||||
|
||||
func NewSessionHandler(repo SessionRepository) *SessionHandler {
|
||||
return &SessionHandler{repo: repo}
|
||||
}
|
||||
|
||||
func (h *SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
path := strings.TrimPrefix(r.URL.Path, "/api/sessions")
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
parts := strings.Split(path, "/")
|
||||
|
||||
if len(parts) >= 2 && parts[1] == "entries" {
|
||||
id, err := parseID(r, "/api/sessions/")
|
||||
if err != nil || id == 0 {
|
||||
respondError(w, http.StatusBadRequest, "session ID required")
|
||||
return
|
||||
}
|
||||
if r.Method == http.MethodPost {
|
||||
h.addEntry(w, r, id)
|
||||
} else {
|
||||
respondError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
id, _ := parseID(r, "/api/sessions/")
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
if id > 0 {
|
||||
h.getByID(w, r, id)
|
||||
} else {
|
||||
h.list(w, r)
|
||||
}
|
||||
case http.MethodPost:
|
||||
h.create(w, r)
|
||||
case http.MethodPut:
|
||||
if id > 0 {
|
||||
h.update(w, r, id)
|
||||
} else {
|
||||
respondError(w, http.StatusBadRequest, "session ID required")
|
||||
}
|
||||
case http.MethodDelete:
|
||||
if id > 0 {
|
||||
h.delete(w, r, id)
|
||||
} else {
|
||||
respondError(w, http.StatusBadRequest, "session ID required")
|
||||
}
|
||||
default:
|
||||
respondError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SessionHandler) list(w http.ResponseWriter, r *http.Request) {
|
||||
sessions, err := h.repo.List(r.Context())
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to list sessions")
|
||||
return
|
||||
}
|
||||
if sessions == nil {
|
||||
sessions = []models.Session{}
|
||||
}
|
||||
respondJSON(w, http.StatusOK, sessions)
|
||||
}
|
||||
|
||||
func (h *SessionHandler) getByID(w http.ResponseWriter, r *http.Request, id int64) {
|
||||
session, err := h.repo.GetByID(r.Context(), id)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to get session")
|
||||
return
|
||||
}
|
||||
if session == nil {
|
||||
respondError(w, http.StatusNotFound, "session not found")
|
||||
return
|
||||
}
|
||||
respondJSON(w, http.StatusOK, session)
|
||||
}
|
||||
|
||||
func (h *SessionHandler) create(w http.ResponseWriter, r *http.Request) {
|
||||
var req models.CreateSessionRequest
|
||||
if err := decodeJSON(r, &req); err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Date.IsZero() {
|
||||
respondError(w, http.StatusBadRequest, "date is required")
|
||||
return
|
||||
}
|
||||
|
||||
session, err := h.repo.Create(r.Context(), &req)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to create session")
|
||||
return
|
||||
}
|
||||
respondJSON(w, http.StatusCreated, session)
|
||||
}
|
||||
|
||||
func (h *SessionHandler) update(w http.ResponseWriter, r *http.Request, id int64) {
|
||||
var req models.CreateSessionRequest
|
||||
if err := decodeJSON(r, &req); err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Date.IsZero() {
|
||||
respondError(w, http.StatusBadRequest, "date is required")
|
||||
return
|
||||
}
|
||||
|
||||
session, err := h.repo.Update(r.Context(), id, &req)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to update session")
|
||||
return
|
||||
}
|
||||
if session == nil {
|
||||
respondError(w, http.StatusNotFound, "session not found")
|
||||
return
|
||||
}
|
||||
respondJSON(w, http.StatusOK, session)
|
||||
}
|
||||
|
||||
func (h *SessionHandler) delete(w http.ResponseWriter, r *http.Request, id int64) {
|
||||
err := h.repo.Delete(r.Context(), id)
|
||||
if err == sql.ErrNoRows {
|
||||
respondError(w, http.StatusNotFound, "session not found")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to delete session")
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h *SessionHandler) addEntry(w http.ResponseWriter, r *http.Request, sessionID int64) {
|
||||
var req models.CreateSessionEntryRequest
|
||||
if err := decodeJSON(r, &req); err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.ExerciseID == 0 {
|
||||
respondError(w, http.StatusBadRequest, "exercise_id is required")
|
||||
return
|
||||
}
|
||||
|
||||
entry, err := h.repo.AddEntry(r.Context(), sessionID, &req)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to add session entry")
|
||||
return
|
||||
}
|
||||
respondJSON(w, http.StatusCreated, entry)
|
||||
}
|
||||
Reference in New Issue
Block a user