package async import ( "encoding/json" "net/http" "predictor-refactored/internal/api/httpjson" "predictor-refactored/internal/api/v2" ) // Handler implements the /api/v1/predictions{,/{id}} endpoints. type Handler struct { mgr *Manager } // NewHandler wires a handler. func NewHandler(mgr *Manager) *Handler { return &Handler{mgr: mgr} } // Register installs the async routes on mux. func (h *Handler) Register(mux *http.ServeMux) { mux.HandleFunc("POST /api/v1/predictions", h.create) mux.HandleFunc("GET /api/v1/predictions/{id}", h.get) mux.HandleFunc("DELETE /api/v1/predictions/{id}", h.cancel) } func (h *Handler) create(w http.ResponseWriter, r *http.Request) { var req v2.PredictionRequest dec := json.NewDecoder(r.Body) dec.DisallowUnknownFields() if err := dec.Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid body: "+err.Error()) return } info, accepted := h.mgr.Enqueue(req) if !accepted { writeJSON(w, http.StatusServiceUnavailable, info) return } w.Header().Set("Location", "/api/v1/predictions/"+info.ID) writeJSON(w, http.StatusAccepted, info) } func (h *Handler) get(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") info, ok := h.mgr.Get(id) if !ok { writeError(w, http.StatusNotFound, "prediction job not found") return } writeJSON(w, http.StatusOK, info) } func (h *Handler) cancel(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if !h.mgr.Cancel(id) { writeError(w, http.StatusConflict, "job not found or already terminal") return } w.WriteHeader(http.StatusNoContent) } var writeJSON = httpjson.Write var writeError = httpjson.Error