I'm trying to make an API call to AlphaVantage's Income Statement endpoint and then unmarshal the response into my IncomeStmt struct. It's not throwing any kind of error but when I try to print the result, I'm getting &{ [] []}
as the value of incomeStmt
.
This is the endpoint: https://www.alphavantage.co/query?function=INCOME_STATEMENT&symbol=IBM&apikey=demo
Here is the API response structure: https://www.alphavantage.co/query?function=INCOME_STATEMENT&symbol=IBM&apikey=demo
So far, I've combed through my IncomeStmt
, QuarterlyReports
and AnnualReports
structs and all the fields match the name and types (all strings according to API structure above) from the API. I checked that I'm exporting all the fields correctly and I believe that my getJson
function is working properly as I've been able to unmarshal a simpler API response using that function. So, I believe the issue is something with how I've created the structs to unmarshal into.
My expected result is to see the API response printed out in fmt.Printf("Unmarshaled IncomeStmt: %v \n", incomeStmt)
from GetIncomeStmt
.
Code Below:
type AnnualReports struct {
FiscalDateEnding string `json:"fiscalDateEnding"`
ReportedCurrency string `json:"reportedCurrency"`
GrossProfit string `json:"grossProfit"`
TotalRevenue string `json:"totalRevenue"`
CostOfRevenue string `json:"costOfRevenue"`
CostOfGoodsAndServicesSold string `json:"costOfGoodsAndServicesSold"`
OperatingIncome string `json:"operatingIncome"`
SellingGeneralAndAdministrative string `json:"sellingGeneralAndAdministrative"`
ResearchAndDevelopment string `json:"researchAndDevelopment"`
OperatingExpenses string `json:"operatingExpenses"`
InvestmentIncomeNet string `json:"investmentIncomeNet"`
NetInterestIncome string `json:"netInterestIncome"`
InterestIncome string `json:"interestIncome"`
InterestExpense string `json:"interestExpense"`
NonInterestIncome string `json:"nonInterestIncome"`
OtherNonOperatingIncome string `json:"otherNonOperatingIncome"`
Depreciation string `json:"depreciation"`
DepreciationAndAmortization string `json:"depreciationAndAmortization"`
IncomeBeforeTax string `json:"incomeBeforeTax"`
IncomeTaxExpense string `json:"incomeTaxExpense"`
InterestAndDebtExpense string `json:"interestAndDebtExpense"`
NetIncomeFromContinuingOperations string `json:"netIncomeFromContinuingOperations"`
ComprehensiveIncomeNetOfTax string `json:"comprehensiveIncomeNetOfTax"`
Ebit string `json:"ebit"`
Ebitda string `json:"ebitda"`
NetIncome string `json:"netIncome"`
}
type QuarterlyReports struct {
FiscalDateEnding string `json:"fiscalDateEnding"`
ReportedCurrency string `json:"reportedCurrency"`
GrossProfit string `json:"grossProfit"`
TotalRevenue string `json:"totalRevenue"`
CostOfRevenue string `json:"costOfRevenue"`
CostOfGoodsAndServicesSold string `json:"costOfGoodsAndServicesSold"`
OperatingIncome string `json:"operatingIncome"`
SellingGeneralAndAdministrative string `json:"sellingGeneralAndAdministrative"`
ResearchAndDevelopment string `json:"researchAndDevelopment"`
OperatingExpenses string `json:"operatingExpenses"`
InvestmentIncomeNet string `json:"investmentIncomeNet"`
NetInterestIncome string `json:"netInterestIncome"`
InterestIncome string `json:"interestIncome"`
InterestExpense string `json:"interestExpense"`
NonInterestIncome string `json:"nonInterestIncome"`
OtherNonOperatingIncome string `json:"otherNonOperatingIncome"`
Depreciation string `json:"depreciation"`
DepreciationAndAmortization string `json:"depreciationAndAmortization"`
IncomeBeforeTax string `json:"incomeBeforeTax"`
IncomeTaxExpense string `json:"incomeTaxExpense"`
InterestAndDebtExpense string `json:"interestAndDebtExpense"`
NetIncomeFromContinuingOperations string `json:"netIncomeFromContinuingOperations"`
ComprehensiveIncomeNetOfTax string `json:"comprehensiveIncomeNetOfTax"`
Ebit string `json:"ebit"`
Ebitda string `json:"ebitda"`
NetIncome string `json:"netIncome"`
}
type IncomeStmt struct {
Symbol string `json:"symbol"`
AnnualReports []AnnualReports `json:"annualReports"`
QuarterlyReports []QuarterlyReports `json:"quarterlyReports"`
}
type Client interface {
GetEarnings(symbol string) (*Earnings, error)
GetIncomeStmt(symbol string) (*IncomeStmt, error)
}
type ClientOpts struct {
ApiKey string
BaseUrl string
HttpClient *http.Client
}
type client struct {
opts ClientOpts
httpClient *http.Client
}
func NewClient(opts ClientOpts) Client {
if opts.ApiKey == "" {
opts.ApiKey = secretProvider.GetEnv("ALPHA_VANTAGE_API_KEY")
}
if opts.BaseUrl == "" {
opts.BaseUrl = secretProvider.GetEnv("ALPHA_VANTAGE_API_BASE_URL")
}
httpClient := opts.HttpClient
if httpClient == nil {
httpClient = &http.Client{Timeout: 10 * time.Second}
}
return &client{
opts: opts,
httpClient: httpClient,
}
}
func (c *client) get(u *url.URL) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
return nil, err
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
// getJson will take the http response and unmarshal it, returning an error if unsuccessful
func getJson(resp *http.Response, data interface{}) error {
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(&data)
}
func (c *client) GetIncomeStmt(symbol string) (*IncomeStmt, error) {
u, err := url.Parse(fmt.Sprintf("%s?function=INCOME_STATEMENT&symbol=%s&apiKey=%s", c.opts.BaseUrl, symbol, c.opts.ApiKey))
if err != nil {
return nil, err
}
resp, err := c.get(u)
if err != nil {
return nil, err
}
incomeStmt := &IncomeStmt{}
if err = getJson(resp, incomeStmt); err != nil {
fmt.Print(err)
log.Fatal("Error decoding data in getJson fn.")
return nil, err
}
fmt.Printf("Unmarshaled IncomeStmt: %v \n", incomeStmt)
return incomeStmt, nil
}