package lexicon import ( "encoding/json" "net/http" "net/url" "github.com/go-chi/chi/v5" ) // Handler serves the word-lookup endpoint backed by a single shared Lexicon. type Handler struct { Lex *Lexicon } // New constructs a Handler with a fresh (lazily-loaded) Lexicon. func NewHandler() *Handler { return &Handler{Lex: New()} } // Routes returns the router mounted at /api/word. The word is a path segment so // "/api/word/happy" reads naturally; it's URL-decoded to tolerate the rare // punctuated token. func (h *Handler) Routes() chi.Router { r := chi.NewRouter() r.Get("/{word}", h.lookup) return r } // GlossRoutes returns the router mounted at /api/gloss — the lightweight // Chinese-only lookup behind the inline hover/select gloss. It shares the // Handler's Lexicon, so the datasets still load just once. func (h *Handler) GlossRoutes() chi.Router { r := chi.NewRouter() r.Get("/{word}", h.gloss) return r } // lookup returns the definition + synonyms for one word. A word found in neither // dataset still returns 200 with empty lists, so the popover can show a friendly // "nothing found" rather than an error state. func (h *Handler) lookup(w http.ResponseWriter, r *http.Request) { word := chi.URLParam(r, "word") if decoded, err := url.PathUnescape(word); err == nil { word = decoded } res, err := h.Lex.Lookup(word) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()}) return } w.Header().Set("Content-Type", "application/json") // Word lookups are static for the life of the build; let the browser cache // them so repeated right-clicks on the same word are instant. w.Header().Set("Cache-Control", "public, max-age=86400") _ = json.NewEncoder(w).Encode(res) } // gloss returns just the Chinese translation for one word. Like lookup, a miss // is a 200 with an empty gloss so the hover tooltip can quietly skip rather than // error. func (h *Handler) gloss(w http.ResponseWriter, r *http.Request) { word := chi.URLParam(r, "word") if decoded, err := url.PathUnescape(word); err == nil { word = decoded } res, err := h.Lex.Gloss(word) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()}) return } w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "public, max-age=86400") _ = json.NewEncoder(w).Encode(res) }