Service Portal widget with third party REST call for address lookup
Thought I would put this article together as it took many searches on Community and Stack Overflow to achieve creating a Service Portal widget with a third party REST call for address lookup. Then interrogating the json response payload through an array and presenting something meaningful back to the end user. Hope someone finds it useful!
Outcome
As an end user I want an address lookup in order to reduce address keying errors and make it easier to find the right address.
To achieve this I'll cover:
- Outbound REST message
- Record producer
- Service Portal widget
- * Body HTML template
- * Capturing an address input to search on
- A search button to trigger the API lookup
- A search button to trigger the API lookup
- Server script
- * Execute the API
- Parse the json API response which is in an array
- Parse the json API response which is in an array
- Client controller
- * Link the search button trigger to the execution of the API and subsequent presentation of results
- * Capturing an address input to search on
Outbound REST message
The best collateral for learning how to create can be found here. https://developer.servicenow.com/dev.do#!/learn/courses/paris/app_store_learnv2_rest_paris_rest_inte...
In this scenario I'm calling an open address finder API where I can pass through a search term &q=${search}
https://api.addressfinder.io/api/nz/address/autocomplete?key=ADDRESSFINDER_DEMO_KEY&secret=ADDRESSFINDER_DEMO_SECRET&q=${search}&format=json&strict=2
REST Message called Address Lookup with an HTTP Method of GET
Example response from API
{
"completions": [
{
"a": "DEMO KEY - replace with your own AddressFinder key",
"pxid": "2-.3.1q.2.3Iuk$",
"v": 1
},
{
"a": "DEMO KEY - replace with your own AddressFinder key",
"pxid": "2-.F.1W.p.0G1Jx",
"v": 0
},
{
"a": "184 William Jones Drive, Otangarei, Whangarei 0112",
"pxid": "2-.9.2U.F.Gogk",
"v": 1
}
],
"paid": false,
"demo": true,
"success": true
}
Record producer
A simple record producer to demonstrate how the widget can be presented in the service portal as part of the overall form submission. In this scenario I'm implying this could be used within CSM for capturing customer addresses when creating a case.
Two variables were created:
- Address widget - Which will capture the address search input from the user and a button to click to searchType = Macro
Widget = Address lookup (which is created in the below steps) - Return address - Which will present the returned results from the API call
* A catalog UI Policy was created to make the Return address variable read only so the result set could maintain it's integrity
Service Portal widget
Body HTML template
Key call out here are:
- Input id='address' that we will reference in the server script to pass the search term
- Button ng-click="c.getAddress();" that we will reference in the client controller
<div class="panel panel-default">
<div class="panel-heading">
${Search address}
</div>
<div class="panel-body">
<div class="input-group">
<input type="text" class="form-control" id="address" placeholder="1 Willis St" ng-model="c.data.address">
<span class="input-group-btn">
<button type="submit" class="btn btn-primary" ng-click="c.getAddress();">Search</button>
</span>
</div>
</div>
</div>
Server script
Key call out here are:
- Transforming the search string to remove spaces and replace with "%20"
- Using JSON.parse to parse the responseBody of the API so we can then interrogate the objects
- Using an array to loop through the responses which were nested under the element of completions (see Example response from API earlier)
- Using a .join("\n") to present each returned result on a new line for readability
- Saving the array of cleaned returned results to data.ReturnAddress for the client controller
(function() {
if (input) {
try {
var r = new sn_ws.RESTMessageV2('Address Lookup', 'Default GET');
//Transform spaces to %20
input.address = input.address.replace(/ /g,"%20");
r.setStringParameterNoEscape('address', input.address);
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
//Loop through JSON for completions.a
var responseJson = JSON.parse(responseBody);
var a = [];
var list = (responseJson.completions).length;
for (var i = 0; i < list; i++) {
var addresses = responseJson.completions[i];
results = addresses.a;
a.push(results);
}
//Save array with line breaks for readability
data.ReturnAddress = a.join("\n");
} catch (ex) {
var message = ex.message;
}
}
})();
Client controller
Key call outs here are:
- Triggering from the c.getAddress() button we created earlier
- Using g_form.setValue(); to take the results from the server script and write to the ReturnAddress variable
function($scope) {
var c = this;
c.getAddress = function()
{
c.server.update().then(function() {
var g_form = $scope.page.g_form;
g_form.setValue('ReturnAddress', c.data.ReturnAddress);
})
}
}
https://www.servicenow.com/community/developer-articles/service-portal-widget-with-third-party-rest-call-for-address/ta-p/2308624