From 1316aa7ca5e1668bbb7967264540bff3c8dbef86 Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Sat, 16 May 2026 22:04:14 -0500 Subject: new api implemented server-side --- api.go | 88 +++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) (limited to 'api.go') diff --git a/api.go b/api.go index fa91ea6..21a2b5f 100644 --- a/api.go +++ b/api.go @@ -1,58 +1,58 @@ package main import ( - "fmt" - "io" "log" + "encoding/json" "net/http" + "time" ) -const youtubeAPI = "https://www.googleapis.com/youtube/v3/" - -/* function to make an api request */ -func apiRequest(w http.ResponseWriter, r *http.Request, endpoint string, videoIdParam string, part string) { - videoID := r.URL.Query().Get("id") - if videoID == "" { - msg := "Missing ?id=VIDEO_ID parameter" - http.Error(w, msg, http.StatusBadRequest) - return - } +type VideoDetails struct { + Channel string `json:"channel"` + DatePublished time.Time `json:"datePublished"` + Description string `json:"description"` + NumComments int `json:"comments"` + NumLikes int `json:"likes"` + NumViews int `json:"views"` + Tags []string `json:"tags"` +} - if apiKey == "" { - msg := "API_KEY environment variable not set" - http.Error(w, msg, http.StatusInternalServerError) - log.Println(msg) - return - } +type Comment struct { + Author string `json:"a"` + Body string `json:"b"` + DatePublished time.Time `json:"p"` + DateUpdated time.Time `json:"u"` + Likes int `json:"l"` + Replies []*Comment `json:"r,omitempty"` +} - url := fmt.Sprintf("%s?part=%s&%s=%s&key=%s", youtubeAPI + endpoint, part, videoIdParam, videoID, apiKey) - resp, err := http.Get(url) - if err != nil { - msg := "Failed to fetch video info: " + err.Error() - http.Error(w, msg, http.StatusInternalServerError) - log.Println(msg) - return - } - defer resp.Body.Close() +type APISource interface { + getDetails(id string) (VideoDetails, error) + getComments(id string) ([]Comment, error) +} - if resp.StatusCode != http.StatusOK { - msg := "YouTube API error: " + resp.Status - http.Error(w, msg, http.StatusBadGateway) - log.Println(msg) - return +func apiDataHandler[T any](f func(id string) (T, error)) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + videoID := r.URL.Query().Get("id") + if videoID == "" { + msg := "Missing ?id=VIDEO_ID parameter" + http.Error(w, msg, http.StatusBadRequest) + return + } + + data, err := f(videoID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + log.Println(err.Error()) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(data) } - - w.Header().Set("Content-Type", "application/json") - io.Copy(w, resp.Body) } -/* routes */ -func setupRoutesAPI() { - http.HandleFunc("/api/details", func(w http.ResponseWriter, r *http.Request) { - apiRequest(w, r, "videos", "id", "snippet,statistics,topicDetails") - }) - - http.HandleFunc("/api/comments", func(w http.ResponseWriter, r *http.Request) { - apiRequest(w, r, "commentThreads", "videoId", "snippet,replies&maxResults=100") - }) +func registerRoutesAPI(mux *http.ServeMux, api APISource) { + mux.HandleFunc("/api/details", apiDataHandler(api.getDetails)) + mux.HandleFunc("/api/comments", apiDataHandler(api.getComments)) } -- cgit v1.2.3