- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 09-22-2020 03:19 PM
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
- Server script
- Execute the API
- 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
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 search
Type = 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);
})
}
}
- 5,191 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks for posting! We have actually done something similar with our portal implementation.
Curious - are there any best practices/recommendations for making outbound REST calls via the portal on a larger scale, e.g., on the portal homepage for every user? We have information that we would like to display to end users but it needs to be a real-time outbound REST call to another system, and we are concerned about page load times and performance.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Ryan - It really does depend on the timeliness AND size of the data you want to return. Take something like a users activity status from MS Teams for example, you probably want this real-time and kept lightweight in payload size for page load times. Versus a users emergency contact details, which are probably larger in size and subject to change less often so could be sufficiently refreshed say every 24 hours. So to mitigate the page load times and performance for that sort of data, options include storing the returned data in a ServiceNow table to be surfaced faster in subsequent page loads then refreshed over API when a time tolerance is reached.
Hope that helps!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
@Nathan Hopkins - Is there a way to use the process in UI Macro? We need to create a similar process but in the Native (ITIL view)
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
This article is a practical guide for integrating a third-party address lookup API into a ServiceNow Service Portal widget. It walks through the full solution—from setting up an outbound REST message and record producer to building a custom widget with client/server scripts.
Key highlights:
Uses a REST API to fetch address suggestions in real-time.
Parses JSON responses and loops through results using arrays.
Presents returned addresses neatly to end users in the portal.
Demonstrates binding between UI elements (search input, button) and the API call.
Great for reducing address entry errors and improving user experience.
A very helpful resource for anyone looking to enhance ServiceNow with external API data!