Go语言消费API时如何将JSON转换为Go类型定义并存储数据
Hey there! Let's work through converting that Alpha Vantage API response into Go structs, especially focusing on the tricky Time Series (1min) field with dynamic timestamp keys. Here's a step-by-step solution that's type-safe and easy to work with for your future calculations.
Step 1: Define Matching Go Structs
First, we'll create structs that mirror the JSON structure. The key insight here is using a map[string]TimeEntry for the time series—since each timestamp is a unique string key, this map will perfectly capture those dynamic entries.
package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "strconv" ) // MetaData maps the "Meta Data" object from the JSON response type MetaData struct { Information string `json:"1. Information"` Symbol string `json:"2. Symbol"` LastRefreshed string `json:"3. Last Refreshed"` Interval string `json:"4. Interval"` OutputSize string `json:"5. Output Size"` TimeZone string `json:"6. Time Zone"` } // TimeEntry represents the price/volume data for a single timestamp type TimeEntry struct { Open string `json:"1. open"` High string `json:"2. high"` Low string `json:"3. low"` Close string `json:"4. close"` Volume string `json:"5. volume"` } // APIResponse is the top-level struct wrapping the entire JSON response type APIResponse struct { MetaData MetaData `json:"Meta Data"` TimeSeries1Min map[string]TimeEntry `json:"Time Series (1min)"` }
Note: The json:"..." tags must exactly match the keys in the JSON, including spaces and number prefixes like "1. open". If you prefer numeric types (like float64 for prices), you can change the fields in TimeEntry to float64/int64—just make sure to handle any parsing errors if the JSON has invalid numbers.
Step 2: Parse the JSON Response with encoding/json
Now update your main function to unmarshal the JSON into our structs. Don't forget to close the response body to avoid resource leaks!
func main() { response, err := http.Get("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=1min&apikey=demo") if err != nil { fmt.Printf("HTTP request failed: %s\n", err) return } defer response.Body.Close() // Critical to free resources data, err := ioutil.ReadAll(response.Body) if err != nil { fmt.Printf("Failed to read response body: %s\n", err) return } // Unmarshal JSON into our APIResponse struct var apiResp APIResponse if err := json.Unmarshal(data, &apiResp); err != nil { fmt.Printf("JSON unmarshal failed: %s\n", err) return } // Example: Access and use the parsed data fmt.Println("Symbol:", apiResp.MetaData.Symbol) fmt.Println("Last Refreshed:", apiResp.MetaData.LastRefreshed) // Loop through time series entries for calculations for timestamp, entry := range apiResp.TimeSeries1Min { // Convert close price to float64 for calculations closePrice, err := strconv.ParseFloat(entry.Close, 64) if err != nil { fmt.Printf("Failed to parse close price for %s: %s\n", timestamp, err) continue } fmt.Printf("Timestamp: %s | Close Price: %.4f\n", timestamp, closePrice) } }
Alternative: Using jsonq (If You Prefer)
Since you were already using jsonq, here's how to extract the time series data with it—though structs are better for type safety long-term:
// Add this import at the top: "github.com/jmoiron/jsonq" func main() { // ... (same HTTP request and read body code as before) jq := jsonq.NewQuery(data) // Extract the time series object timeSeries, err := jq.Object("Time Series (1min)") if err != nil { fmt.Printf("Failed to get time series: %s\n", err) return } // Iterate through each timestamp entry for timestamp, entry := range timeSeries { entryMap := entry.(map[string]interface{}) closePrice, _ := jq.String(entryMap, "4. close") fmt.Printf("%s: Close = %s\n", timestamp, closePrice) } }
Key Takeaways
- Dynamic fields: Use
map[string]YourStructwhen JSON has keys that change (like timestamps here). - Type safety: Structs are always preferred over raw
map[string]interface{}because they enforce data types and make code more maintainable. - Error handling: Always check for errors during HTTP requests, reading bodies, and unmarshaling—this saves you from silent failures later.
内容的提问来源于stack exchange,提问作者Philip Mutua

