- C#
- Python
- NodeJS
Address Validation 3 C# Code Snippet
using AV3Service;
using System;
using System.Threading.Tasks;
namespace address_validation_us_3_dot_net.SOAP
{
/// <summary>
/// A simple wrapper class to call the AV3 GetBestMatches SOAP
/// operation endpoint (with primary/backup failover and an “IsLive” toggle).
/// </summary>
public class GetBestMatchesValidation
{
private const string LiveBaseUrl = "https://sws.serviceobjects.com/av3/api.svc/soap";
private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/av3/api.svc/soap";
private const string TrailBaseUrl = "https://trial.serviceobjects.com/av3/api.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 GetBestMatchesValidation(bool IsLive)
{
// Read timeout (milliseconds) and IsLive flag
_timeoutMs = 10000;
_isLive = IsLive;
if (_isLive)
{
_primaryUrl = LiveBaseUrl;
_backupUrl = BackupBaseUrl;
}
else
{
_primaryUrl = TrailBaseUrl;
_backupUrl = TrailBaseUrl;
}
if (string.IsNullOrWhiteSpace(_primaryUrl))
throw new InvalidOperationException("Primary URL not set. Check endpoint configuration.");
if (string.IsNullOrWhiteSpace(_backupUrl))
throw new InvalidOperationException("Backup URL not set. Check endpoint configuration.");
}
/// <summary>
/// Calls the GetBestMatches SOAP operation. If the primary endpoint returns null
/// or a fatal Error.TypeCode == "3", this will fall back to the backup endpoint.
/// </summary>
/// <param name="businessName">Business name (or empty if none)</param>
/// <param name="address1">Street address line 1</param>
/// <param name="address2">Street address line 2 (or empty)</param>
/// <param name="city">City</param>
/// <param name="state">State (2‑letter or full state name)</param>
/// <param name="zip">ZIP or ZIP+4</param>
/// <param name="licenseKey">Your ServiceObjects Address Validation US 3 license key</param>
/// <returns>A BestMatchesResponse containing an array of Address objects (or an Error)</returns>
/// <exception cref="Exception">
/// Thrown if both primary and backup endpoints fail.
/// </exception>
public async Task<BestMatchesResponse> GetBestMatches(
string businessName,
string address1,
string address2,
string city,
string state,
string zip,
string licenseKey
)
{
AddressValidation3Client clientPrimary = null;
AddressValidation3Client clientBackup = null;
try
{
// 1) Attempt Primary
clientPrimary = new AddressValidation3Client();
clientPrimary.Endpoint.Address = new System.ServiceModel.EndpointAddress(_primaryUrl);
clientPrimary.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);
BestMatchesResponse response = await clientPrimary.GetBestMatchesAsync(
businessName,
address1,
address2,
city,
state,
zip,
licenseKey
).ConfigureAwait(false);
// If the response is null, or if a “fatal” Error.TypeCode == "3" came back, force a fallback
if (response == null || (response.Error != null && response.Error.TypeCode == "3"))
{
throw new InvalidOperationException("Primary endpoint returned null or a fatal TypeCode=3 error for GetBestMatches.");
}
return response;
}
catch (Exception primaryEx)
{
// 2) Primary failed (due to exception, null, or TypeCode=3). Try Backup.
try
{
clientBackup = new AddressValidation3Client();
clientBackup.Endpoint.Address = new System.ServiceModel.EndpointAddress(_backupUrl);
clientBackup.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);
return await clientBackup.GetBestMatchesAsync(
businessName,
address1,
address2,
city,
state,
zip,
licenseKey
).ConfigureAwait(false);
}
catch (Exception backupEx)
{
// If backup also fails, wrap both exceptions
throw new Exception(
$"Both primary and backup endpoints failed.\n" +
$"Primary error: {primaryEx.Message}\n" +
$"Backup error: {backupEx.Message}"
);
}
finally
{
clientBackup?.Close();
}
}
finally
{
clientPrimary?.Close();
}
}
}
}
Address Validation US 3 Python Code Snippet
from suds.client import Client
from suds import WebFault
from suds.sudsobject import Object
class GetBestMatchesValidation:
def __init__(self, license_key: str, is_live: bool, timeout_ms: int = 10000):
"""
license_key (str): Service Objects Address Validation US - 3 license key.
is_live (bool): whether to use live or trial endpoints.
timeout_ms (int): SOAP call timeout in milliseconds.
"""
self._timeout_s = timeout_ms / 1000.0
self._is_live = is_live
self.license_key = license_key
# WSDL URLs
self._primary_wsdl = (
"https://sws.serviceobjects.com/AV3/api.svc?wsdl"
if is_live else
"https://trial.serviceobjects.com/AV3/api.svc?wsdl"
)
self._backup_wsdl = (
"https://swsbackup.serviceobjects.com/AV3/api.svc?wsdl"
if is_live else
"https://trial.serviceobjects.com/AV3/api.svc?wsdl"
)
def get_best_matches(self,
business_name: str,
address1: str,
address2: str,
city: str,
state: str,
postal_code: str) -> Object:
"""
Calls GetBestMatches on the primary endpoint; on None response,
WebFault, or Error.TypeCode == '3' falls back to the backup endpoint.
returns: the suds response object
raises RuntimeError: if both endpoints fail
"""
# Common kwargs for both calls
call_kwargs = dict(
BusinessName=business_name,
Address=address1,
Address2=address2,
City=city,
State=state,
PostalCode=postal_code,
LicenseKey=self.license_key
)
# Attempt primary
try:
client = Client(self._primary_wsdl, timeout=self._timeout_s)
# Override endpoint URL if needed:
response = client.service.GetBestMatches(**call_kwargs)
# If response is None or fatal error code, trigger fallback
if response is None or (hasattr(response, 'Error') and response.Error and response.Error.TypeCode == '3'):
raise ValueError("Primary returned no result or fatal Error.TypeCode=3")
return response
except (WebFault, ValueError, Exception) as primary_ex:
# Attempt backup
try:
client = Client(self._backup_wsdl, timeout=self._timeout_s)
response = client.service.GetBestMatches(**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: {primary_ex}\n"
f"Backup error: {backup_ex}"
)
raise RuntimeError(msg)
Address Validation 3 NodeJS Code Snippet
import { soap } from 'strong-soap';
/**
* <summary>
* A class that provides functionality to call the ServiceObjects Address Validation (AV3) SOAP service's GetBestMatches endpoint,
* retrieving validated and corrected address information for a parsed U.S. address with fallback to a backup endpoint for reliability in live mode.
* </summary>
*/
class GetBestMatchesSoap {
/**
* <summary>
* Initializes a new instance of the GetBestMatchesSoap class with the provided input parameters,
* setting up primary and backup WSDL URLs based on the live/trial mode.
* </summary>
* @param {string} BusinessName - Name of business associated with this address. Optional.
* @param {string} Address - Address line 1 of the address (e.g., "123 Main Street"). Required.
* @param {string} Address2 - Address line 2 of the address (e.g., "Apt 4B"). Optional.
* @param {string} City - The city of the address (e.g., "New York"). Optional, but required if PostalCode is not provided.
* @param {string} State - The state of the address (e.g., "NY"). Optional, but required if PostalCode is not provided.
* @param {string} PostalCode - The zip code of the address. Optional, but required if City and State are not provided.
* @param {string} LicenseKey - Your license key to use the service. Required.
* @param {boolean} isLive - Value to determine whether to use the live or trial servers. Defaults to true.
* @param {number} timeoutSeconds - Timeout, in seconds, for the call to the service. Defaults to 15.
* @throws {Error} Thrown if LicenseKey is empty or null.
*/
constructor(BusinessName, Address, Address2, City, State, PostalCode, LicenseKey, isLive = true, timeoutSeconds = 15) {
this.args = {
BusinessName,
Address,
Address2,
City,
State,
PostalCode,
LicenseKey
};
this.isLive = isLive;
this.timeoutSeconds = timeoutSeconds;
this.LiveBaseUrl = 'https://sws.serviceobjects.com/AV3/api.svc?wsdl';
this.BackupBaseUrl = 'https://swsbackup.serviceobjects.com/AV3/api.svc?wsdl';
this.TrialBaseUrl = 'https://trial.serviceobjects.com/AV3/api.svc?wsdl';
this._primaryWsdl = this.isLive ? this.LiveBaseUrl : this.TrialBaseUrl;
this._backupWsdl = this.isLive ? this.BackupBaseUrl : this.TrialBaseUrl;
}
/**
* <summary>
* Asynchronously calls the GetBestMatches SOAP endpoint, attempting the primary endpoint
* first and falling back to the backup if the response is invalid (Error.TypeCode == '3') in live mode
* or if the primary call fails.
* </summary>
* @returns {Promise<Object>} A promise that resolves to the raw SOAP response data containing validated address details or an error.
* @throws {Error} Thrown if both primary and backup calls fail, with detailed error messages.
*/
async invokeAsync() {
try {
const primaryResult = await this._callSoap(this._primaryWsdl, this.args);
if (this.isLive && !this._isValid(primaryResult)) {
console.warn("Primary returned Error.TypeCode == '3', falling back to backup...");
const backupResult = await this._callSoap(this._backupWsdl, this.args);
return backupResult;
}
return primaryResult;
} catch (primaryErr) {
try {
console.warn("Primary call failed, falling back to backup...");
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 returning the raw SOAP response data.
* </summary>
* @param {string} wsdlUrl - The WSDL URL of the SOAP service endpoint (primary or backup).
* @param {Object} args - The arguments to pass to the GetBestMatches method.
* @returns {Promise<Object>} A promise that resolves to the raw SOAP response data.
* @throws {Error} Thrown if the SOAP client creation fails, the service call fails, or the response cannot be parsed.
*/
_callSoap(wsdlUrl, args) {
return new Promise((resolve, reject) => {
soap.createClient(wsdlUrl, { timeout: this.timeoutSeconds * 1000 }, (err, client) => {
if (err) return reject(err);
client.GetBestMatches(args, (err, result) => {
const response = result?.GetBestMatchesResult;
try {
if (!response) {
return reject(new Error("SOAP response is empty or undefined."));
}
resolve(response);
} 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.TypeCode is not equal to '3'.
* </summary>
* @param {Object} response - The raw response object to validate.
* @returns {boolean} True if the response is valid, false otherwise.
*/
_isValid(response) {
return response && (!response.Error || response.Error.TypeCode !== '3');
}
}
export { GetBestMatchesSoap };