feat(api): add /api/radio stub returning the seed track only
M6 stub. Validates seed_track param (400 on missing/blank/bad UUID), looks up the track (404 on miss), returns RadioResponse with a single TrackRef. M4 will replace the body with similarity-driven candidate pool + scoring; the request/response shape is final.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
||||
)
|
||||
|
||||
// RadioResponse is the body of GET /api/radio.
|
||||
type RadioResponse struct {
|
||||
Tracks []TrackRef `json:"tracks"`
|
||||
}
|
||||
|
||||
// handleRadio implements GET /api/radio?seed_track=<uuid>.
|
||||
//
|
||||
// M6 stub: returns a queue containing only the seed track. The full M4
|
||||
// implementation (similarity-based candidate pool + scoring) replaces the
|
||||
// body without changing the request/response shape.
|
||||
func (h *handlers) handleRadio(w http.ResponseWriter, r *http.Request) {
|
||||
raw := strings.TrimSpace(r.URL.Query().Get("seed_track"))
|
||||
if raw == "" {
|
||||
writeErr(w, http.StatusBadRequest, "bad_request", "seed_track is required")
|
||||
return
|
||||
}
|
||||
id, ok := parseUUID(raw)
|
||||
if !ok {
|
||||
writeErr(w, http.StatusBadRequest, "bad_request", "invalid seed_track id")
|
||||
return
|
||||
}
|
||||
q := dbq.New(h.pool)
|
||||
track, err := q.GetTrackByID(r.Context(), id)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
writeErr(w, http.StatusNotFound, "not_found", "seed_track not found")
|
||||
return
|
||||
}
|
||||
h.logger.Error("api: get radio seed track failed", "err", err)
|
||||
writeErr(w, http.StatusInternalServerError, "server_error", "lookup failed")
|
||||
return
|
||||
}
|
||||
album, err := q.GetAlbumByID(r.Context(), track.AlbumID)
|
||||
if err != nil {
|
||||
h.logger.Error("api: get radio seed album failed", "err", err)
|
||||
writeErr(w, http.StatusInternalServerError, "server_error", "lookup failed")
|
||||
return
|
||||
}
|
||||
artist, err := q.GetArtistByID(r.Context(), track.ArtistID)
|
||||
if err != nil {
|
||||
h.logger.Error("api: get radio seed artist failed", "err", err)
|
||||
writeErr(w, http.StatusInternalServerError, "server_error", "lookup failed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, RadioResponse{
|
||||
Tracks: []TrackRef{trackRefFrom(track, album.Title, artist.Name)},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user