- C#
- Python
- NodeJS
Address Geocode – US C# Code Snippet
using AGUSService;
using System.Text.RegularExpressions;
namespace address_geocode_us_dot_net.SOAP
{
/// <summary>
/// Provides functionality to call the ServiceObjects Address Geocode US (AGUS) SOAP service's GetBestMatch_V4 operation,
/// retrieving geocoding information (e.g., latitude, longitude, ZIP code) for a given US address with fallback to a backup endpoint
/// for reliability in live mode.
/// </summary>
public class GetBestMatchV4Validation
{
private const string LiveBaseUrl = "https://sws.serviceobjects.com/GCR/soap.svc/SOAP";
private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/GCR/soap.svc/SOAP";
private const string TrialBaseUrl = "https://trial.serviceobjects.com/GCR/soap.svc/SOAP";
private readonly string _primaryUrl;
private readonly string _backupUrl;
private readonly int _timeoutMs;
private readonly bool _isLive;
/// <summary>
/// Initializes URLs/timeout/IsLive.
/// </summary>
public GetBestMatchV4Validation(bool isLive)
{
_timeoutMs = 10000;
_isLive = isLive;
_primaryUrl = isLive ? LiveBaseUrl : TrialBaseUrl;
_backupUrl = isLive ? BackupBaseUrl : TrialBaseUrl;
if (string.IsNullOrWhiteSpace(_primaryUrl))
throw new InvalidOperationException("Primary URL not set.");
if (string.IsNullOrWhiteSpace(_backupUrl))
throw new InvalidOperationException("Backup URL not set.");
}
/// <summary>
/// Async, returns the latitude and longitude for a given US address. This operation will use cascading logic when an exact address match is not found and it will return the next closest level match available. The operation output is designed to allow the service to return new pieces of data as they become available without having to re-integrate.
/// </summary>
/// <param name="Address">Address line of the address to geocode. For example, “123 Main Street”.</param>
/// <param name="City">The city of the address to geocode. For example, “New York”. The city isn’t required, but if one is not provided, the Zip code is required.</param>
/// <param name="State">The state of the address to geocode. For example, “NY”. This does not need to be contracted, full state names will work as well. The state isn’t required, but if one is not provided, the Zip code is required.</param>
/// <param name="PostalCode">The zip code of the address to geocode. A zip code isn’t required, but if one is not provided, the City and State are required.</param>
/// <param name="LicenseKey">Your license key to use the service.</param>
public async Task<Location_V4> GetBestMatchV4(string Address, string City, string State, string PostalCode, string LicenseKey)
{
GCRSoapServiceClient clientPrimary = null;
GCRSoapServiceClient clientBackup = null;
try
{
// Attempt Primary
clientPrimary = new GCRSoapServiceClient();
clientPrimary.Endpoint.Address = new System.ServiceModel.EndpointAddress(_primaryUrl);
clientPrimary.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);
Location_V4 response = await clientPrimary.GetBestMatch_V4Async(
Address, City, State, PostalCode, LicenseKey).ConfigureAwait(false);
if (_isLive && !IsValid(response))
{
throw new InvalidOperationException("Primary endpoint returned null or a fatal Number=4 error for GetBestMatch_V4");
}
return response;
}
catch (Exception primaryEx)
{
try
{
clientBackup = new GCRSoapServiceClient();
clientBackup.Endpoint.Address = new System.ServiceModel.EndpointAddress(_backupUrl);
clientBackup.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);
return await clientBackup.GetBestMatch_V4Async(
Address, City, State, PostalCode, LicenseKey).ConfigureAwait(false);
}
catch (Exception backupEx)
{
throw new InvalidOperationException(
$"Both primary and backup endpoints failed.\n" +
$"Primary error: {primaryEx.Message}\n" +
$"Backup error: {backupEx.Message}");
}
finally
{
clientBackup?.Close();
}
}
finally
{
clientPrimary?.Close();
}
}
private static bool IsValid(Location_V4 response) => response?.Error == null || response.Error.Number != "4";
}
}
Address Geocode – US Python Code Snippet
from sre_parse import State
from suds.client import Client
from suds import WebFault
from suds.sudsobject import Object
class GetBestMatchV4Soap:
def __init__(self, address: str, city: str, state: str, postal_code: str, license_key: str, is_live: bool = True, timeout_ms: int = 15000):
"""
Initialize the GetBestMatchV4Soap client with input parameters and set up primary and backup WSDL URLs.
Parameters:
address: Address line of the address to geocode (e.g., "123 Main Street").
city: The city of the address to geocode (e.g., "New York"). Optional if postal code is provided.
state: The state of the address to geocode (e.g., "NY"). Optional if postal code is provided.
postal_code: The ZIP code of the address to geocode. Optional if city and state are provided.
license_key: Your ServiceObjects license key.
is_live: Determines whether to use the live or trial servers.
timeout_ms: Timeout, in milliseconds, for the call to the service.
Raises:
ValueError: If LicenseKey is empty or null.
"""
self.is_live = is_live
self.timeout = timeout_ms / 1000.0
self.license_key=license_key
self.address=address
self.city=city
self.state=state
self.postal_code=postal_code
# WSDL URLs
self._primary_wsdl = (
'https://sws.serviceobjects.com/gcr/soap.svc?wsdl'
if is_live else
'https://trial.serviceobjects.com/gcr/soap.svc?wsdl'
)
self._backup_wsdl = (
'https://swsbackup.serviceobjects.com/gcr/soap.svc?wsdl'
if is_live else
'https://trial.serviceobjects.com/gcr/soap.svc?wsdl'
)
def get_best_match_v4(self) -> Object:
"""
Calls the GetBestMatch_V4 SOAP endpoint, attempting the primary endpoint first and falling back
to the backup if the response is invalid (Error.TypeCode == '4') in live mode or if the primary call fails.
Returns:
suds.sudsobject.Object: SOAP response containing geocoding details or error.
Raises:
RuntimeError: If both primary and backup calls fail, with detailed error messages.
"""
# Common kwargs for both calls
call_kwargs = dict(
Address=self.address,
City=self.city,
State=self.state,
PostalCode=self.postal_code,
LicenseKey=self.license_key,
)
# Attempt primary
try:
client = Client(self._primary_wsdl)
response = client.service.GetBestMatch_V4(**call_kwargs)
# If response invalid or Error.Number == "4", trigger fallback
if response is None or (hasattr(response, "Error") and response.Error and response.Error.Number == "4"):
raise ValueError("Primary returned no result or Error.Number=4")
return response
except (WebFault, ValueError, Exception) as primary_ex:
try:
client = Client(self._backup_wsdl)
response = client.service.GetBestMatch_V4(**call_kwargs)
if response is None:
raise ValueError("Backup returned no result")
return response
except (WebFault, Exception) as backup_ex:
msg = (
"Both primary and backup endpoints failed.\n"
f"Primary error: {str(primary_ex)}\n"
f"Backup error: {str(backup_ex)}"
)
raise RuntimeError(msg)
Address Geocode – US NodeJS Code Snippet
import { soap } from 'strong-soap';
/**
* <summary>
* A class that provides functionality to call the ServiceObjects Address Geocode US (AGUS) SOAP service's GetBestMatch_V4 endpoint,
* retrieving geocoding information (e.g., latitude, longitude, ZIP code) for a given US address with fallback to a backup endpoint for reliability in live mode.
* </summary>
*/
class GetBestMatchV4Soap {
/**
* <summary>
* Initializes a new instance of the GetBestMatchV4Soap class with the provided input parameters,
* setting up primary and backup WSDL URLs based on the live/trial mode.
* </summary>
* @param {string} Address - Address line of the address to geocode. For example, "123 Main Street".
* @param {string} City - The city of the address to geocode. For example, "New York".
* @param {string} State - The state of the address to geocode. For example, "NY".
* @param {string} PostalCode - The zip code of the address to geocode.
* @param {string} LicenseKey - Your license key to use the service.
* @param {boolean} isLive - Value to determine whether to use the live or trial servers.
* @param {number} timeoutSeconds - Timeout, in seconds, for the call to the service.
* @throws {Error} Thrown if LicenseKey is empty or null.
*/
constructor(Address, City, State, PostalCode, LicenseKey, isLive = true, timeoutSeconds = 15) {
this.args = {
Address,
City,
State,
PostalCode,
LicenseKey
};
this.isLive = isLive;
this.timeoutSeconds = timeoutSeconds;
this.LiveBaseUrl = "https://sws.serviceobjects.com/gcr/soap.svc?wsdl";
this.BackupBaseUrl = "https://swsbackup.serviceobjects.com/gcr/soap.svc?wsdl";
this.TrialBaseUrl = "https://trial.serviceobjects.com/gcr/soap.svc?wsdl";
this._primaryWsdl = this.isLive ? this.LiveBaseUrl : this.TrialBaseUrl;
this._backupWsdl = this.isLive ? this.BackupBaseUrl : this.TrialBaseUrl;
}
/**
* <summary>
* Asynchronously calls the GetBestMatch_V4 SOAP endpoint, attempting the primary endpoint
* first and falling back to the backup if the response is invalid (Error.Number == '4') in live mode
* or if the primary call fails.
* </summary>
* <returns type="Promise<LocationV4Response>">A promise that resolves to a LocationV4Response object containing geocoding details or an error.</returns>
* <exception cref="Error">Thrown if both primary and backup calls fail, with detailed error messages.</exception>
*/
async invokeAsync() {
try {
const primaryResult = await this._callSoap(this._primaryWsdl, this.args);
if (this.isLive && !this._isValid(primaryResult)) {
console.warn("Primary returned Error.Number == '4', falling back to backup...");
const backupResult = await this._callSoap(this._backupWsdl, this.args);
return backupResult;
}
return primaryResult;
} catch (primaryErr) {
try {
const backupResult = await this._callSoap(this._backupWsdl, this.args);
return backupResult;
} catch (backupErr) {
throw new Error(`Both primary and backup calls failed:\nPrimary: ${primaryErr.message}\nBackup: ${backupErr.message}`);
}
}
}
/**
* <summary>
* Performs a SOAP service call to the specified WSDL URL with the given arguments,
* creating a client and processing the response into a LocationV4Response object.
* </summary>
* <param name="wsdlUrl" type="string">The WSDL URL of the SOAP service endpoint (primary or backup).</param>
* <param name="args" type="Object">The arguments to pass to the GetBestMatch_V4 method.</param>
* <returns type="Promise<LocationV4Response>">A promise that resolves to a LocationV4Response object containing the SOAP response data.</returns>
* <exception cref="Error">Thrown if the SOAP client creation fails, the service call fails, or the response cannot be parsed.</exception>
*/
_callSoap(wsdlUrl, args) {
return new Promise((resolve, reject) => {
soap.createClient(wsdlUrl, { timeout: this.timeoutSeconds * 1000 }, (err, client) => {
if (err) return reject(err);
client.GetBestMatch_V4(args, (err, result) => {
const rawData = result?.GetBestMatch_V4Result;
try {
if (!rawData) {
return reject(new Error("SOAP response is empty or undefined."));
}
resolve(rawData);
} catch (parseErr) {
reject(new Error(`Failed to parse SOAP response: ${parseErr.message}`));
}
});
});
});
}
/**
* <summary>
* Checks if a SOAP response is valid by verifying that it exists and either has no Error object
* or the Error.Number is not equal to '4'.
* </summary>
* <param name="response" type="LocationV4Response">The LocationV4Response object to validate.</param>
* <returns type="boolean">True if the response is valid, false otherwise.</returns>
*/
_isValid(response) {
return response && (!response.Error || response.Error.Number !== '4');
}
}
export { GetBestMatchV4Soap };