Address Suggestion with embedded USPS Address Validation
Customers who use our DOTS Global Address Complete, our address type-ahead functionality, also benefit from our DOTS Address Validation – US 3 API which is embedded with the service. Previous blog articles including “Introducing Global Address Complete” and “Enhancing Global Address Complete with Address Validation – US” go into more detail about how address lookup works, so we will keep the discussion short and only focus on how you can also add international address validation to our address suggestion service.
The data that powers the type-ahead functionality is different from the data that powers Address Validation – US 3 functionality, which is why we have combined these products. What this really means is that the type-ahead functionality does not guarantee a valid mailable US address by itself, so upon selecting one of the address suggestions you can have that address validated with our world-class Address Validation – US 3 product, if that is option you choose to turn on.
What doesn’t come our Address Suggestion service?
As the name, Global Address Complete suggests, it should work for global addresses, so why is it that Address Validation – US 3 is embedded and not Address Validation – International? The reason is that the international address validation product wasn’t a good fit to embed directly due to the additional costs and potential performance impacts. Pulling Address Validation – International into our global address verification service may still happen in the future, in the meantime, we offer a simple workaround that enables you to validate a selected address from Global Address Complete.
Adding international address validation to Global Address Complete
We can still validate global addresses using our Address Validation – International service. Below is a quick guide to bringing these two services together.
But before we get started, let’s go over some critical differences in the license keys for Global Address Complete and Address Validation – International. Going over this now will help the integration make sense when we are putting together the solution.
Global Address Complete license keys are different from the license keys we use with the rest of our offerings. Since address auto-complete integrates primarily into Javascript, exposing license keys is a security concern. With Javascript, anyone who knows enough to right click on a web page and view the source code will be able to see and extract license keys. Special protection needs to be taken with these kinds of keys. The way we protect these keys is through custom keys that can be locked down to particular domains. If anyone swipes the custom key, it cannot be used elsewhere.
License keys to our other APIs, like Address Validation – International, are not typically used in Javascript. Those APIs and their keys tend to be used in back-end situations where the keys cannot be easily exposed. This difference in license keys is important, because in our solution we will be bringing these two types together, and we will need to find a solution that allows us to work in Javascript for part of the solution and in the back end for the other part of the solution.
Integration via front and back end
The beginning of this integration will start with largely the same integration, where you set up Global Address Complete and map the fields, you can follow A Quick Guide to Global Address Complete and then come back to this guide for the integration with international address validation.
Where we depart from that blog and continue on here is when we want to start listening in the Javascript for the event to populate. The populate event usually just lets the front end populate with the selected address from the type-ahead functionality. However, this event also allows us to capture the address that’s been selected before it gets populated to the UI and validate the address.
To validate an address using the Address Validation – International API we need to make sure we are capturing all the address data points from the selected address that the validation API requires. We set up some variables to receive the selected suggested address from Global Address Complete, and then populate them with the address variables from the service inside the populate event.
DOTSGlobalAddressComplete.listen("populate", function (address, variations) { var Address = ''; var Address2 = ''; var Address3 = ''; var Address4 = ''; var Address5 = ''; var Locality = ''; var AdministrativeArea = ''; var PostalCode = ''; var Country = ''; var Language = ''; Address = address.Address1; Address2 = address.Address2; Address3 = address.Address3; Address4 = address.Address4; Address5 = address.Address5; Locality = address.Locality; AdministrativeArea = address.AdminArea; PostalCode = address.PostalCode; Country = address.CountryIso3; Language = 'English'; CallAddressValidationInternational(Address, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, Language, address); });
Once we have gathered all of the variables needed for the call to the Address Validation – International service, we send them to the method for handling the call, CallAddressValidationInternational.
First, we check to see what country the address was associated with. Since Global Address Complete comes with US address validation, we only need to send addresses to Address Validation – International that are not in the US.
Next, for addresses that are outside of the US, we set up a call to a back-end proxy that will call the Address Validation – International API. The reason for this is connected to what we mentioned earlier regarding how the two different APIs license keys are secured. The Global Address Complete license keys are secured by domain so they can be listed in the Javascript. Global address validation keys are not secured by domain and are used on the back end. So, by setting up a proxy call to a back end web method we can keep the license key nicely hidden. We’ll let that back-end call append the license key to the call to Address Validation – International call instead.
In the code you will see us building up the call to the back end by pulling in the address parameters and adding them to the data field of the Ajax call we are going to make to the back end. In our situation the data field must match the order of parameters as in the signature for the back-end web method. This is how we have the data field set up.
var Data = '{Address1: "' + Address + '", Address2: "' + Address2 + '", Address3: "' + Address3 + '", Address4: "' + Address4 + '", Address5: "' + Address5 + '", Locality: "' + Locality + '", AdministrativeArea: "' + AdministrativeArea + '", PostalCode: "' + PostalCode + '", Country: "' + Country + '", OutputLanguage: "' + Language + '"}';
Note that we have not used a license key in any of the parameters.
Since we are working with ASP.Net, we have made a back-end web method called ValidateAddressLive on our helper aspx page called AVIHandler. The AVIHandler.aspx does not have a UI, it simply facilitates a pace to expose a web method. We are more interested in the AVIHandler.aspx.cs page. In AVIHandler.aspx.cs, we create a web method that accepts the same parameters as those that we set up for the data field.
[WebMethod] public static string ValidateAddressLive(string Address1, string Address2, string Address3, string Address4, string Address5, string Locality, string AdministrativeArea, string PostalCode, string Country, string OutputLanguage)
In here we also set up the SOAP references so we can deal with strongly typed variables when it comes to dealing with the API. You could also call the service via Restful calls, in which case you would need to either parse a JSON or XML response, which is simple enough as well. The call to the API in this back-end web method will start with setting up the client, pulling the API key from a web config file, making the call to the API, and then returning the results back to the Javascript for further processing.
AVITrial.AVISoapServiceClient ws = new AVITrial.AVISoapServiceClient(); AVITrial.AddressInfoResponse response = default(AVITrial.AddressInfoResponse); try { Key = ConfigurationManager.AppSettings["AVIKey"]; WEB_SERVICE_REQUEST_TIMEOUT = Convert.ToInt32(ConfigurationManager.AppSettings["WebServiceRequestTimeout"]); ws.InnerChannel.OperationTimeout = new TimeSpan(0, 0, 0, WEB_SERVICE_REQUEST_TIMEOUT); response = ws.GetAddressInfo(Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, Key); if (response == null) { return ""; } string json = new JavaScriptSerializer().Serialize(response); return json; } catch (Exception e) { return ""; } finally { if (ws != null) { ws.Close(); } }
When we get back to the Ajax method in the Javascript, we determine if the results that we got back from the Address Validation – International API require us to make a failover call or not. A failover call is necessary to ensure uptime. In the case of an unexpected error or some sort of network issue stopping the call to the main endpoint, a call to the backup endpoint will help ensure that you always get a response back from the service. The call to the backup endpoint for the API can be coded the same way on the back end, but with just a different endpoint, and this code can be written in many different ways. Here is the code in the Javascript.
$.ajax( { type: "POST", url: "AVIHandler.aspx/ValidateAddressLive", data: Data, contentType: "application/json; charset=utf-8", success: function (response) { if (response.d !== "") { var statResult = JSON.parse(response.d) document.getElementById("LabelJSON").innerText = address.FormattedAddress; document.getElementById("FullResponseJSON").innerText = JSON.stringify(address, null, '\t') + '\r\n\r\n' + JSON.stringify(statResult, null, '\t'); if ($('#ExpLabel').hasClass('Hide')) { $('#ExpLabel').removeClass('Hide').addClass('Show'); } if ($('#ExpResponse').hasClass('Hide')) { $('#ExpResponse').removeClass('Hide').addClass('Show'); } } else { handleError(Data); } }, error: function (e) { handleError(Data); } });
And the handleError Javascript function:
function handleError(Data) { $.ajax({ type: "POST", url: "AVIHandler.aspx/ValidateAddressBackUp", data: Data, contentType: "application/json; charset=utf-8", success: function (response) { if (response.d !== "") { var statResult = JSON.parse(response.d) document.getElementById("LabelJSON").innerText = address.FormattedAddress; document.getElementById("FullResponseJSON").innerText = JSON.stringify(address, null, '\t') + '\r\n\r\n' + JSON.stringify(statResult, null, '\t'); if ($('#ExpLabel').hasClass('Hide')) { $('#ExpLabel').removeClass('Hide').addClass('Show'); } if ($('#ExpResponse').hasClass('Hide')) { $('#ExpResponse').removeClass('Hide').addClass('Show'); } } }, error: function (e) { } }); }
And the back-end failover web method:
[WebMethod] public static string ValidateAddressBackup(string Address1, string Address2, string Address3, string Address4, string Address5, string Locality, string AdministrativeArea, string PostalCode, string Country, string OutputLanguage) { AVITrialBackup.AVISoapServiceClient ws = new AVITrialBackup.AVISoapServiceClient(); AVITrialBackup.AddressInfoResponse response = default(AVITrialBackup.AddressInfoResponse); try { Key = ConfigurationManager.AppSettings["AVIKey"]; WEB_SERVICE_REQUEST_TIMEOUT = Convert.ToInt32(ConfigurationManager.AppSettings["WebServiceRequestTimeout"]); ws.InnerChannel.OperationTimeout = new TimeSpan(0, 0, 0, WEB_SERVICE_REQUEST_TIMEOUT); response = ws.GetAddressInfo(Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, Key); if (response == null) { return ""; } string json = new JavaScriptSerializer().Serialize(response); return json; } catch (Exception e) { return ""; } finally { if (ws != null) { ws.Close(); } } }
So that does it. See the accompanying code for a fully flushed out example of what we presented above. If you have any questions about the service, please reach out and we’ll be happy to go over it with you.