diff options
| author | wikiapiserver | 2026-06-25 15:42:32 +0200 |
|---|---|---|
| committer | wikiapiserver | 2026-06-25 15:42:32 +0200 |
| commit | 81258d39db6530699194f860206528c6f09a5238 (patch) | |
| tree | 015290ae2f28e1f8123c0efecfea078f80d2ff70 | |
| parent | 1a25a89dfeeb7ed5af4df77907b65f99bdf5399a (diff) | |
| download | wikiapiserver-81258d39db6530699194f860206528c6f09a5238.tar.gz | |
feat: GET /article endpoint proxies Wikimedia structured contents
GET /article?username=alice&name=en.wikipedia/Sun
→ proxies to api.enterprise.wikimedia.com/v2/structured-contents/{name}
with Authorization: Bearer <access_token>
Returns 401 for unknown users, 400 if params missing,
and passes through the upstream HTTP status on errors.
| -rw-r--r-- | api/handlers.go | 49 | ||||
| -rw-r--r-- | main.go | 1 |
2 files changed, 50 insertions, 0 deletions
diff --git a/api/handlers.go b/api/handlers.go index 0f3b48b..6813dc2 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -2,11 +2,13 @@ package api import ( "context" + "io" "database/sql" "errors" "encoding/json" "log" "net/http" + "net/url" "time" "wikiapiserver/db" @@ -202,3 +204,50 @@ func (h *Handler) GetToken(w http.ResponseWriter, r *http.Request) { ValidUntil: acct.AccessTokenExpiry.Add(24 * time.Hour).Format(time.RFC3339), }) } +// --- Get Article: GET /article?username=...&name=... --- + +func (h *Handler) GetArticle(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second) + defer cancel() + + username := r.URL.Query().Get("username") + article := r.URL.Query().Get("name") + if username == "" || article == "" { + badRequest(w, "username and name query parameters are required") + return + } + + acct, err := h.db.GetAccount(ctx, username) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + unauthorized(w) + return + } + serverError(w, "could not retrieve token") + return + } + + url := "https://api.enterprise.wikimedia.com/v2/structured-contents/" + url.QueryEscape(article) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + serverError(w, "could not build request") + return + } + req.Header.Set("Authorization", "Bearer "+acct.AccessToken) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + serverError(w, "wikimedia api error") + return + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + b, _ := io.ReadAll(resp.Body) + http.Error(w, string(b), resp.StatusCode) + return + } + + w.Header().Set("Content-Type", "application/json") + io.Copy(w, resp.Body) //nolint:errcheck +} @@ -87,6 +87,7 @@ func main() { mux.HandleFunc("POST /refresh", handler.Refresh) mux.HandleFunc("GET /health", handler.Health) mux.HandleFunc("GET /token", handler.GetToken) + mux.HandleFunc("GET /article", handler.GetArticle) addr := fmt.Sprintf(":%d", cfg.Server.Port) srv := &http.Server{ |
