feat(world/yahoo): forward validated range+interval → daily series
handleYahooFinance now forwards a whitelisted range/interval to Yahoo's chart endpoint (e.g. range=1y&interval=1d) instead of always returning the intraday default. Absent params preserve prior behavior; the range keys the cache so different spans of a symbol cache separately. Unlocks real 1-year daily growth charts on lux.fund (was intraday-only).
This commit is contained in:
@@ -161,7 +161,16 @@ func (s *Server) handleYahooFinance(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
upstream := "https://query1.finance.yahoo.com/v8/finance/chart/" + urlQueryEscape(sym)
|
||||
s.passthrough(w, "yahoo:"+sym, upstream, "application/json",
|
||||
cacheKey := "yahoo:" + sym
|
||||
// Forward a validated range/interval so callers can ask for a daily series
|
||||
// (e.g. range=1y&interval=1d) instead of the intraday default. Absent params
|
||||
// keep the prior behavior; the range is part of the cache key so different
|
||||
// spans of the same symbol cache separately.
|
||||
if q := yahooChartQuery(r); q != "" {
|
||||
upstream += "?" + q
|
||||
cacheKey += ":" + q
|
||||
}
|
||||
s.passthrough(w, cacheKey, upstream, "application/json",
|
||||
"public, max-age=60, s-maxage=60, stale-while-revalidate=30",
|
||||
map[string]string{"User-Agent": browserUA},
|
||||
60*time.Second, 5*time.Minute,
|
||||
@@ -170,6 +179,29 @@ func (s *Server) handleYahooFinance(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
var yahooRanges = map[string]bool{
|
||||
"1d": true, "5d": true, "1mo": true, "3mo": true, "6mo": true,
|
||||
"1y": true, "2y": true, "5y": true, "10y": true, "ytd": true, "max": true,
|
||||
}
|
||||
var yahooIntervals = map[string]bool{
|
||||
"1m": true, "2m": true, "5m": true, "15m": true, "30m": true, "60m": true,
|
||||
"90m": true, "1h": true, "1d": true, "5d": true, "1wk": true, "1mo": true, "3mo": true,
|
||||
}
|
||||
|
||||
// yahooChartQuery returns a validated range/interval query string for Yahoo's
|
||||
// chart endpoint, or "" when the caller supplies neither (preserving the intraday
|
||||
// default). Only whitelisted values pass through.
|
||||
func yahooChartQuery(r *http.Request) string {
|
||||
parts := make([]string, 0, 2)
|
||||
if rng := lower(trimSpace(r.URL.Query().Get("range"))); yahooRanges[rng] {
|
||||
parts = append(parts, "range="+rng)
|
||||
}
|
||||
if itv := lower(trimSpace(r.URL.Query().Get("interval"))); yahooIntervals[itv] {
|
||||
parts = append(parts, "interval="+itv)
|
||||
}
|
||||
return strings.Join(parts, "&")
|
||||
}
|
||||
|
||||
func validateSymbol(sym string) string {
|
||||
sym = upper(trimSpace(sym))
|
||||
if sym == "" || len(sym) > 20 {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestYahooChartQuery(t *testing.T) {
|
||||
cases := []struct{ q, want string }{
|
||||
{"?symbol=SMH&range=1y&interval=1d", "range=1y&interval=1d"},
|
||||
{"?symbol=SMH", ""}, // default preserved
|
||||
{"?symbol=SMH&range=bogus&interval=1d", "interval=1d"}, // bad range dropped
|
||||
{"?symbol=SMH&range=1Y&interval=1D", "range=1y&interval=1d"}, // case-normalized
|
||||
{"?symbol=SMH&range=5y", "range=5y"},
|
||||
{"?symbol=SMH&interval=evil", ""}, // bad interval dropped
|
||||
}
|
||||
for _, c := range cases {
|
||||
r := httptest.NewRequest("GET", "/v1/world/yahoo-finance"+c.q, nil)
|
||||
if got := yahooChartQuery(r); got != c.want {
|
||||
t.Errorf("yahooChartQuery(%q) = %q, want %q", c.q, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -2,7 +2,11 @@
|
||||
"name": "@hanzo/world",
|
||||
"description": "Hanzo World — real-time global intelligence dashboard.",
|
||||
"private": true,
|
||||
"version": "2.4.43",
|
||||
<<<<<<< HEAD
|
||||
"version": "2.4.39",
|
||||
=======
|
||||
"version": "2.4.38",
|
||||
>>>>>>> d2b5a7d8 (feat(world/yahoo): forward validated range+interval → daily series)
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"lint:md": "markdownlint-cli2 '**/*.md'",
|
||||
|
||||
Reference in New Issue
Block a user