Following the previous article on
how to better design libraries in IBM RPA, let's build an IBM RPA
connector to
AccuWeather API, specifically the
Forecast API and
Locations API.
To use the APIs, we need an
API Key. So, first, you need to
register. Then you need to
create an app within AccuWeather selecting the "
Limited Trial" option. Save your API Key.
We won't build an entire connector for every API available. For demonstration purposes, we will build the connector for 2 APIs:
- City Search using the Locations API.
- 5 Days of Daily Forecasts using the Forecast API.
Here is the implemented
AccuWeather.wal connector. Further down we explain it.
defVar --name apiKey --type String --parameter
defVar --name locationKey --type String --parameter
defVar --name isDebug --type Boolean
defVar --name methodNames --type List --innertype String --parameter
defVar --name methodName --type String --parameter
defVar --name success --type Boolean
defVar --name httpResponse --type String
defVar --name httpStatusCode --type Numeric
defVar --name httpReasonPhrase --type String
defVar --name iconMapping --type StringDictionary --innertype String
defVar --name forecasts --type DataTable --output
defVar --name forecastHeadline --type String --output
defVar --name i --type Numeric
defVar --name mapJsonKey --type String
defVar --name forecastDay --type String
defVar --name dateText --type String
defVar --name forecastDate --type DateTime
defVar --name forecastUnit --type String
defVar --name forecastMinTemperature --type Numeric
defVar --name forecastMaxTemperature --type Numeric
defVar --name forecastIconId --type String
defVar --name forecastIconPhrase --type String
defVar --name forecastIcon --type String
defVar --name query --type String --parameter
defVar --name locations --type DataTable --output
defVar --name jsonTable --type DataTable
defVar --name jsonRegion --type String
defVar --name jsonCountry --type String
defVar --name locationCountry --type String
defVar --name locationRegion --type String
defVar --name locationCity --type String
#region debug data
executeScript --name Utils --parameters "methodName=IsDebug" --output "isDebug=${isDebug}" --comment "methods: IsDebug"
setVarIf --variablename "${apiKey}" --value "<MY API KEY>" --left "${isDebug}" --operator "Is_True"
//setVarIf --variablename "${methodName}" --value SearchCities --left "${isDebug}" --operator "Is_True"
//setVarIf --variablename "${locationKey}" --value 858642 --left "${isDebug}" --operator "Is_True"
//setVarIf --variablename "${query}" --value "sao paulo" --left "${isDebug}" --operator "Is_True"
#endregion
#region validating
case --switches "CaseSwitchesAll"
when --left "${methodName}" --operator "Is_Null_Or_Empty"
when --left "${methodNames}" --operator "Is_Empty"
then
failTest --message "The parameter \'methodName\' or \'methodNames\' is required and was not specified"
endCase
#endregion
if --left "${methodName}" --operator "Is_Null_Or_Empty" --negate
add --collection "${methodNames}" --value "${methodName}"
endIf
foreach --collection "${methodNames}" --variable "${methodName}" --distinct
goSub --label "${methodName}"
endFor
beginSub --name SearchCities
httpRequest --verb "Get" --url "http://dataservice.accuweather.com/locations/v1/cities/search?apikey=${apiKey}&q=${query}" --cookiecontainer --noproxy success=success httpResponse=value httpStatusCode=statusCode httpReasonPhrase=reasonPhrase
assert --message "Request failed with \"${httpStatusCode}\": ${httpReasonPhrase}" --left "${success}" --operator "Is_True"
gosubIf --label __LogHttpResponse --left "${isDebug}" --operator "Is_True"
goSub --label __BuildLocations
endSub
beginSub --name DailyForecasts
httpRequest --verb "Get" --url "http://dataservice.accuweather.com/forecasts/v1/daily/5day/${locationKey}?apikey=${apiKey}&metric=true" --cookiecontainer --noproxy success=success httpResponse=value httpStatusCode=statusCode httpReasonPhrase=reasonPhrase
assert --message "Request failed with \"${httpStatusCode}\": ${httpReasonPhrase}" --left "${success}" --operator "Is_True"
gosubIf --label __LogHttpResponse --left "${isDebug}" --operator "Is_True"
goSub --label __IconMapping
goSub --label __BuildForecasts
endSub
beginSub --name __LogHttpResponse
logMessage --message "\r\n${httpResponse}" --type "Info"
endSub
beginSub --name __IconMapping
strDictAdd --key 1 --value "https://developer.accuweather.com/sites/default/files/01-s.png" --dictionary ${iconMapping}
strDictAdd --key 2 --value "https://developer.accuweather.com/sites/default/files/02-s.png" --dictionary ${iconMapping}
strDictAdd --key 3 --value "https://developer.accuweather.com/sites/default/files/03-s.png" --dictionary ${iconMapping}
strDictAdd --key 4 --value "https://developer.accuweather.com/sites/default/files/04-s.png" --dictionary ${iconMapping}
strDictAdd --key 5 --value "https://developer.accuweather.com/sites/default/files/05-s.png" --dictionary ${iconMapping}
strDictAdd --key 6 --value "https://developer.accuweather.com/sites/default/files/06-s.png" --dictionary ${iconMapping}
strDictAdd --key 7 --value "https://developer.accuweather.com/sites/default/files/07-s.png" --dictionary ${iconMapping}
strDictAdd --key 8 --value "https://developer.accuweather.com/sites/default/files/08-s.png" --dictionary ${iconMapping}
strDictAdd --key 11 --value "https://developer.accuweather.com/sites/default/files/11-s.png" --dictionary ${iconMapping}
strDictAdd --key 12 --value "https://developer.accuweather.com/sites/default/files/12-s.png" --dictionary ${iconMapping}
strDictAdd --key 13 --value "https://developer.accuweather.com/sites/default/files/13-s.png" --dictionary ${iconMapping}
strDictAdd --key 14 --value "https://developer.accuweather.com/sites/default/files/14-s.png" --dictionary ${iconMapping}
strDictAdd --key 15 --value "https://developer.accuweather.com/sites/default/files/15-s.png" --dictionary ${iconMapping}
strDictAdd --key 16 --value "https://developer.accuweather.com/sites/default/files/16-s.png" --dictionary ${iconMapping}
strDictAdd --key 17 --value "https://developer.accuweather.com/sites/default/files/17-s.png" --dictionary ${iconMapping}
strDictAdd --key 18 --value "https://developer.accuweather.com/sites/default/files/18-s.png" --dictionary ${iconMapping}
strDictAdd --key 20 --value "https://developer.accuweather.com/sites/default/files/20-s.png" --dictionary ${iconMapping}
strDictAdd --key 21 --value "https://developer.accuweather.com/sites/default/files/21-s.png" --dictionary ${iconMapping}
strDictAdd --key 22 --value "https://developer.accuweather.com/sites/default/files/22-s.png" --dictionary ${iconMapping}
strDictAdd --key 23 --value "https://developer.accuweather.com/sites/default/files/23-s.png" --dictionary ${iconMapping}
strDictAdd --key 24 --value "https://developer.accuweather.com/sites/default/files/24-s.png" --dictionary ${iconMapping}
strDictAdd --key 25 --value "https://developer.accuweather.com/sites/default/files/25-s.png" --dictionary ${iconMapping}
strDictAdd --key 26 --value "https://developer.accuweather.com/sites/default/files/26-s.png" --dictionary ${iconMapping}
strDictAdd --key 29 --value "https://developer.accuweather.com/sites/default/files/29-s.png" --dictionary ${iconMapping}
strDictAdd --key 30 --value "https://developer.accuweather.com/sites/default/files/30-s.png" --dictionary ${iconMapping}
strDictAdd --key 31 --value "https://developer.accuweather.com/sites/default/files/31-s.png" --dictionary ${iconMapping}
strDictAdd --key 32 --value "https://developer.accuweather.com/sites/default/files/32-s.png" --dictionary ${iconMapping}
strDictAdd --key 33 --value "https://developer.accuweather.com/sites/default/files/33-s.png" --dictionary ${iconMapping}
strDictAdd --key 34 --value "https://developer.accuweather.com/sites/default/files/34-s.png" --dictionary ${iconMapping}
strDictAdd --key 35 --value "https://developer.accuweather.com/sites/default/files/35-s.png" --dictionary ${iconMapping}
strDictAdd --key 36 --value "https://developer.accuweather.com/sites/default/files/36-s.png" --dictionary ${iconMapping}
strDictAdd --key 37 --value "https://developer.accuweather.com/sites/default/files/37-s.png" --dictionary ${iconMapping}
strDictAdd --key 38 --value "https://developer.accuweather.com/sites/default/files/38-s.png" --dictionary ${iconMapping}
strDictAdd --key 39 --value "https://developer.accuweather.com/sites/default/files/39-s.png" --dictionary ${iconMapping}
strDictAdd --key 40 --value "https://developer.accuweather.com/sites/default/files/40-s.png" --dictionary ${iconMapping}
strDictAdd --key 41 --value "https://developer.accuweather.com/sites/default/files/41-s.png" --dictionary ${iconMapping}
strDictAdd --key 42 --value "https://developer.accuweather.com/sites/default/files/42-s.png" --dictionary ${iconMapping}
strDictAdd --key 43 --value "https://developer.accuweather.com/sites/default/files/43-s.png" --dictionary ${iconMapping}
strDictAdd --key 44 --value "https://developer.accuweather.com/sites/default/files/44-s.png" --dictionary ${iconMapping}
endSub
beginSub --name __BuildForecasts
addColumn --dataTable ${forecasts} --columnname Date --type DateTime
addColumn --dataTable ${forecasts} --columnname Minimum --type Numeric
addColumn --dataTable ${forecasts} --columnname Maximum --type Numeric
addColumn --dataTable ${forecasts} --columnname Unit --type String
addColumn --dataTable ${forecasts} --columnname Icon --type String
addColumn --dataTable ${forecasts} --columnname Text --type String
mapJson --json "${httpResponse}" --mappings "$.Headline.Text=${forecastHeadline}"
for --variable ${i} --from 0 --to 5 --step 1
setVar --name "${mapJsonKey}" --value "$.DailyForecasts[${i}]" --comment "this is required because of this bug: https://jsw.ibm.com/browse/DBACLD-43741"
mapJson --handleError --json "${httpResponse}" --mappings "${mapJsonKey}=${forecastDay}" success=value
if --left "${success}" --operator "Is_True" --negate
break
endIf
mapJson --json "${forecastDay}" --mappings "$.Date=${dateText}"
textToDateTime --culture "en-US" --text "${dateText}" --usecustomformat --customformat "M/d/yyyy h:mm:ss tt" forecastDate=value
mapJson --json "${forecastDay}" --mappings "$.Temperature.Minimum.Unit=${forecastUnit}"
mapJson --json "${forecastDay}" --mappings "$.Temperature.Minimum.Value=${forecastMinTemperature}"
mapJson --json "${forecastDay}" --mappings "$.Temperature.Maximum.Value=${forecastMaxTemperature}"
mapJson --json "${forecastDay}" --mappings "$.Day.Icon=${forecastIconId}"
strDictGet --key "${forecastIconId}" --dictionary ${iconMapping} forecastIcon=value
mapJson --json "${forecastDay}" --mappings "$.Day.IconPhrase=${forecastIconPhrase}"
addRow --valuesmapping "Date=${forecastDate},Minimum=${forecastMinTemperature},Maximum=${forecastMaxTemperature},Icon=${forecastIcon},Text=${forecastIconPhrase},Unit=${forecastUnit}" --dataTable ${forecasts}
next
endSub
beginSub --name __BuildLocations
addColumn --dataTable ${locations} --columnname Key --type String
addColumn --dataTable ${locations} --columnname Region --type String
addColumn --dataTable ${locations} --columnname Country --type String
addColumn --dataTable ${locations} --columnname City --type String
jsonToTable --json "${httpResponse}" --jsonPath "$" jsonTable=value
for --variable ${i} --from 1 --to ${jsonTable.Rows} --step 1
mapTableRow --dataTable ${jsonTable} --row ${i} --mappings "name=Key=${locationKey},name=EnglishName=${locationCity},name=Region=${jsonRegion},name=Country=${jsonCountry}"
mapJson --json "${jsonCountry}" --mappings "$.EnglishName=${locationCountry}"
mapJson --json "${jsonRegion}" --mappings "$.EnglishName=${locationRegion}"
addRow --valuesmapping "Key=${locationKey},Region=${locationRegion},Country=${locationCountry},City=${locationCity}" --dataTable ${locations}
next
endSub
This exposes
2 methods:
SearchCities
implementing
City Search.
Parameters
- String
apiKey
- String
query
Outputs
- DataTable
locations
with the following columns: String Key
, String Region
, String Country
and String City
DailyForecasts
implementing
5 Days of Daily Forecasts.
Parameters
- String
apiKey
- String
locationKey
retrieved from Key
column of SearchCities
locations
output.
Outputs
- String
forecastHeadline
- DataTable
forecasts
with the following columns: DateTime Date
, Numeric Minimum
, Numeric Maximum
, String Unit
, String Icon
, String Text
.
Notice that we have
private methods in
AccuWeather script. We name those methods with a double underscore prefix, like
__BuildLocations
. That was a good practice to build libraries, so we explicitly say which methods are public and which are private.
We also used the
Utils library created in the last article, to query whether we are running in
debug mode. This allows us to test the script with hardcoded data using the
setVarIf command. Using such command with
isDebug
condition won't require us to change the library before publishing it to production.
Okay, how can I use it?SearchCities
:
executeScript --name AccuWeather --parameters "methodName=SearchCities,query=london" --output "locations=${locations}"
//loop through the data table
for --variable ${i} --from 1 --to ${locations.Rows} --step 1
if --left "${i}" --operator "Equal_To" --right 5 --comment "get only 5 cities"
break
endIf
mapTableRow --dataTable ${locations} --row ${i} --mappings "name=Key=${locationKey},name=Region=${locationRegion},name=Country=${locationCountry},name=City=${locationCity}"
next
DailyForecasts
:
executeScript --name AccuWeather --parameters "methodName=DailyForecasts,locationKey=${userAnswer}" --output "forecasts=${forecasts},forecastHeadline=${forecastHeadline}"
mapTableRow --dataTable ${forecasts} --row 1 --mappings "name=Minimum=${forecastMinimum},name=Maximum=${forecastMaximum},name=Text=${forecastText},name=Unit=${forecastUnit}"
Shouldn't we fetch the Api Key
from the Control Center parameters?We could, but that is not the responsibility of the library. If we did that, we would require everyone to create such parameter before using the library. Instead, we provided the flexibility to consumers to pass the parameter in any form they wish to.
We demonstrated how we can create connectors in IBM RPA using good development practices. Stay tuned to find out how to use such libraries within a chatbot.