PureBasic and AccuWeather APIs - A LIVE Working Example
Posted: Mon Aug 11, 2025 9:18 am
I had posted some examples earlier, demonstrating the use of REST APIs, through PureBasic's HTTP library, as well as the more conventional Network library, mostly consuming demo APIs on my own servers.
This example demonstrates the use of publicly available APIs, namely from AccuWeather, to retrieve daily weather forecasts. It uses a static, preconfigured list of city/state values from a text file downloaded from my server, then queries two API services from AccuWeather to retrieve the daily forecasts of the selected cities.
The fine-grained nature of AccuWeather's services, which attempts to offer pinpoint accuracy, employs the use of location keys. Instead of returning forecast reports based on city/state queries, it drills down to more precise latitude/longitude geopositioning, where a single city/state could correspond to multiple location keys. However, it also indexes city/state entries to common, perhaps more central, location keys, which could be queried just by the city/state names.
Nevertheless, it still requires calls to two APIs, one for retrieving the location key, and another for retrieving the actual forecast report. The following examples demonstrate these two API calls, which could be directly called from the address bar of any browser.
> the first API call to retrieve the location key for Rome/Italy:
> the second API call to retrieve the daily forecast for Rome/Italy (location key = 213490 returned from the above API call):
Here is the full working code, a modification of my earlier timeanddate.com example. For convenience, I have included the API key from one of my AccuWeather accounts, but I'm sure it would exceed the 50 daily call-limit in no time. To test it effectively, please register for a free-tier account and utilise that API key instead.
This example demonstrates the use of publicly available APIs, namely from AccuWeather, to retrieve daily weather forecasts. It uses a static, preconfigured list of city/state values from a text file downloaded from my server, then queries two API services from AccuWeather to retrieve the daily forecasts of the selected cities.
It should be noted that AccuWeather APIs require unique API keys in order to work. To obtain an API key, simply register for a free-tier account with them, which allows up to 50 API calls per day.
> AccuWeather API Packages
The fine-grained nature of AccuWeather's services, which attempts to offer pinpoint accuracy, employs the use of location keys. Instead of returning forecast reports based on city/state queries, it drills down to more precise latitude/longitude geopositioning, where a single city/state could correspond to multiple location keys. However, it also indexes city/state entries to common, perhaps more central, location keys, which could be queried just by the city/state names.
Nevertheless, it still requires calls to two APIs, one for retrieving the location key, and another for retrieving the actual forecast report. The following examples demonstrate these two API calls, which could be directly called from the address bar of any browser.
> the first API call to retrieve the location key for Rome/Italy:
Code: Select all
http://dataservice.accuweather.com/locations/v1/cities/search?apikey=[insert API key here]&q=rome%2Citaly
> the second API call to retrieve the daily forecast for Rome/Italy (location key = 213490 returned from the above API call):
Code: Select all
http://dataservice.accuweather.com/forecasts/v1/daily/1day/213490?apikey=[insert API key here]&metric=true
Here is the full working code, a modification of my earlier timeanddate.com example. For convenience, I have included the API key from one of my AccuWeather accounts, but I'm sure it would exceed the 50 daily call-limit in no time. To test it effectively, please register for a free-tier account and utilise that API key instead.
Code: Select all
;==========================================================
;
; AccuWeather REST API example:
; - retrieving location keys from city/state names
; - retrieivng weather forecasts with location keys
;
; * an API key is required to run this example which
; can be obtained with a free-tier registration
; https://developer.accuweather.com/packages
;
; * an API key has been included for testing but
; is limited to only 50 API calls per day
;
; tested & working on:
; 1. Windows 8.1 w/ PureBasic 5.73 LTS (x64)
; 2. Windows 10 w/ PureBasic 6.11 LTS (x64)
; 3. Windows 11 w/ PureBasic 6.21 (x64)
; 4. macOS Catalina w/ PureBasic 5.73 LTS (x64)
; 5. macOS Sonoma w/ PureBasic 6.11 LTS (arm64)
; 6. macOS Sequoia w/ PureBasic 6.21 (arm64)
; 7. Ubuntu Linux 18.04.2 w/ PureBasic 6.11 LTS (x64)
;
; by TI-994A - free to use, improve, share...
;
; 10th August 2025 - Singapore
;
;==========================================================
EnableExplicit
CompilerIf #PB_Compiler_Version < 600
InitNetwork()
CompilerEndIf
#API_URL = "http://dataservice.accuweather.com/"
#API_Key = "oMBJLzGG3g2tkUwy5z6BgApVL2e9WGqL"
#API_Key_Invalid = "Api Authorization failed"
#API_Exceed = "The allowed number of requests has been exceeded."
#httpSuccess = 200
Define event, appQuit, cityList, cityLabel, forecastLabel, forecastDescriptionLabel
Procedure initData()
Shared cityList
Dim cities.s(149)
Define i, citiesFile.s
citiesFile = GetTemporaryDirectory() + "cities.txt"
If FileSize(citiesFile) < 1
ReceiveHTTPFile("syed.sg/tutorials/cities.txt", citiesFile)
EndIf
If ReadFile(0, citiesFile)
While Eof(0) = 0
cities(i) = Trim(ReadString(0))
i + 1
Wend
CloseFile(0)
EndIf
For i = 0 To 149
AddGadgetItem (cityList, -1, cities(i))
Next i
EndProcedure
Procedure validResponse(response.s)
Define valid = #True
If FindString(response, #API_Exceed) > 0
valid = #False
MessageRequester("AccuWeather API Error", #API_Exceed)
ElseIf FindString(response, #API_Key_Invalid) > 0
valid = #False
MessageRequester("AccuWeather API Error", "Invalid API Key!")
EndIf
ProcedureReturn valid
EndProcedure
Procedure.s getLocationKey(locationResults)
Define i, jsonObject, countryElement
Define.s countryName, locationKey
For i = 0 To JSONArraySize(locationResults) - 1
jsonObject = GetJSONElement(locationResults, i)
countryElement = GetJSONMember(jsonObject, "Country")
countryName = GetJSONString(GetJSONMember(countryElement, "EnglishName"))
locationKey = GetJSONString(GetJSONMember(jsonObject, "Key"))
Break
Next i
ProcedureReturn locationKey
EndProcedure
Procedure getForecast(city.s, forecastResults)
Shared cityLabel, forecastLabel, forecastDescriptionLabel
Define.d minTemp, maxTemp, forecastDescription.s
Define i, forecastHeader, forecastArray, forecast, temperatures
forecastHeader = GetJSONMember(forecastResults, "Headline")
forecastDescription = GetJSONString(GetJSONMember(forecastHeader, "Text"))
forecastArray.i = GetJSONMember(forecastResults, "DailyForecasts")
For i = 0 To JSONArraySize(forecastArray) - 1
forecast = GetJSONElement(forecastArray, i)
temperatures = GetJSONMember(forecast, "Temperature")
minTemp = GetJSONDouble(GetJSONMember(GetJSONMember(temperatures, "Minimum"), "Value"))
maxTemp = GetJSONDouble(GetJSONMember(GetJSONMember(temperatures, "Maximum"), "Value"))
Break
Next i
SetGadgetText(cityLabel, city)
SetGadgetText(forecastLabel, "" + minTemp + " / " + maxTemp + " °C")
SetGadgetText(forecastDescriptionLabel, forecastDescription)
EndProcedure
Procedure accuWeather(city.s)
Define.s weatherURL, locationURL, cityQuery, locationKey, serverResponse, httpRequest.i
cityQuery = ReplaceString(ReplaceString(city, ", ", "%2C"), " ", "%20")
locationURL = #API_URL + "locations/v1/cities/search?q=" + LCase(cityQuery) + "&apikey=" + #API_Key
httpRequest = HTTPRequest(#PB_HTTP_Get, locationURL)
If httpRequest
If Val(HTTPInfo(httpRequest, #PB_HTTP_StatusCode)) = #httpSuccess
serverResponse = HTTPInfo(httpRequest, #PB_HTTP_Response)
If validResponse(serverResponse)
locationKey = getLocationKey(JSONValue(ParseJSON(#PB_Any, serverResponse)))
If Trim(locationKey) <> ""
weatherURL = #API_URL + "forecasts/v1/daily/1day/" + locationKey + "?metric=true&apikey=" + #API_Key
httpRequest = HTTPRequest(#PB_HTTP_Get, weatherURL)
If httpRequest
If Val(HTTPInfo(httpRequest, #PB_HTTP_StatusCode)) = #httpSuccess
serverResponse = HTTPInfo(httpRequest, #PB_HTTP_Response)
If validResponse(serverResponse)
getForecast(city, JSONValue(ParseJSON(#PB_Any, serverResponse)))
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndProcedure
OpenWindow(0, 0, 0, 1000, 500, "AccuWeather API Demo",
#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
cityList = ListViewGadget(#PB_Any, 10, 10, 350, 420)
cityLabel = TextGadget(#PB_Any, 400, 30, 480, 100, "Select a city...")
forecastLabel = TextGadget(#PB_Any, 450, 135, 530, 300, "High / Low")
forecastDescriptionLabel = TextGadget(#PB_Any, 10, 460, 980, 30, #API_URL, #PB_Text_Center)
If LoadFont(0, "Arial", 30)
SetGadgetFont(cityLabel, FontID(0))
EndIf
If LoadFont(1, "Arial", 70)
SetGadgetFont(forecastLabel, FontID(1))
EndIf
If LoadFont(2, "Arial", 20)
SetGadgetFont(forecastDescriptionLabel, FontID(2))
EndIf
initData()
Repeat
event = WaitWindowEvent()
Select event
Case #PB_Event_CloseWindow
appQuit = #True
Case #PB_Event_Gadget
Select EventGadget()
Case cityList
If EventType() = #PB_EventType_LeftClick
accuWeather(GetGadgetText(cityList))
EndIf
EndSelect
EndSelect
Until appQuit