Address Validation International C# Code Snippet

using System;
using System.Threading.Tasks;
using AVIReference;

namespace address_validation_international_dot_net.SOAP
{
    /// <summary>
    /// Provides functionality to call the ServiceObjects Address Validation International (AVI) SOAP service's GetAddressInfo operation,
    /// retrieving validated and corrected international address information with fallback to a backup endpoint for reliability in live mode.
    /// </summary>
    public class GetAddressInfoValidation
    {
        private const string LiveBaseUrl = "https://sws.serviceobjects.com/avi/soap.svc/SOAP";
        private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/avi/soap.svc/SOAP";
        private const string TrialBaseUrl = "https://trial.serviceobjects.com/avi/soap.svc/SOAP";

        private readonly string _primaryUrl;
        private readonly string _backupUrl;
        private readonly int _timeoutMs;
        private readonly bool _isLive;

        /// <summary>
        /// Initializes URLs, timeout, and IsLive.
        /// </summary>
        public GetAddressInfoValidation(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>
        /// This operation returns validated and corrected international address information for a given address,
        /// including formatted address lines, locality, administrative area, postal code, country details, and additional information components.
        /// </summary>
        /// <param name="Address1">Address line 1 of the international address.</param>
        /// <param name="Address2">Address line 2 of the international address. Optional.</param>
        /// <param name="Address3">Address line 3 of the international address. Optional.</param>
        /// <param name="Address4">Address line 4 of the international address. Optional.</param>
        /// <param name="Address5">Address line 5 of the international address. Optional.</param>
        /// <param name="Locality">The city, town, or municipality of the address. Required if postal code is not provided.</param>
        /// <param name="AdministrativeArea">The state, region, or province of the address. Required if postal code is not provided.</param>
        /// <param name="PostalCode">The postal code of the address. Required if locality and administrative area are not provided.</param>
        /// <param name="Country">The country name or ISO 3166-1 Alpha-2/Alpha-3 code.</param>
        /// <param name="OutputLanguage">The language for service output (e.g., "ENGLISH", "BOTH", "LOCAL_ROMAN", "LOCAL").</param>
        /// <param name="LicenseKey">The license key to authenticate the API request.</param>
        public async Task<AddressInfoResponse> GetAddressInfo(string Address1, string Address2, string Address3, string Address4, string Address5, string Locality, string AdministrativeArea, string PostalCode, string Country, string OutputLanguage, string LicenseKey)
        {
            AVISoapServiceClient clientPrimary = null;
            AVISoapServiceClient clientBackup = null;

            try
            {
                // Attempt Primary
                clientPrimary = new AVISoapServiceClient();
                clientPrimary.Endpoint.Address = new System.ServiceModel.EndpointAddress(_primaryUrl);
                clientPrimary.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);

                AddressInfoResponse response = await clientPrimary.GetAddressInfoAsync(
                    Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, LicenseKey).ConfigureAwait(false);

                if (_isLive && !ValidResponse(response))
                {
                    throw new InvalidOperationException("Primary endpoint returned null or a fatal TypeCode=3 error for GetAddressInfo");
                }
                return response;
            }
            catch (Exception primaryEx)
            {
                try
                {
                    clientBackup = new AVISoapServiceClient();
                    clientBackup.Endpoint.Address = new System.ServiceModel.EndpointAddress(_backupUrl);
                    clientBackup.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);

                    return await clientBackup.GetAddressInfoAsync(
                        Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, 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 ValidResponse(AddressInfoResponse response)
        {
            return response?.Error == null || response.Error.TypeCode != "3";
        }
    }
}

Address Validation International Python Code Snippet

from suds.client import Client
from suds import WebFault
from suds.sudsobject import Object

class GetAddressInfoSoap:
    def __init__(self, license_key: str, is_live: bool = True, timeout_ms: int = 15000):
        """
        license_key: Service Objects AVI license key.
        is_live: Whether to use live or trial endpoints.
        timeout_ms: SOAP call timeout in milliseconds.
        """
        self.is_live = is_live
        self.timeout = timeout_ms / 1000.0
        self.license_key = license_key

        # WSDL URLs
        self._primary_wsdl = (
            "https://sws.serviceobjects.com/avi/soap.svc?wsdl"
            if is_live
            else "https://trial.serviceobjects.com/avi/soap.svc?wsdl"
        )
        self._backup_wsdl = (
            "https://swsbackup.serviceobjects.com/avi/soap.svc?wsdl"
            if is_live
            else "https://trial.serviceobjects.com/avi/soap.svc?wsdl"
        )

    def get_address_info(
        self,
        address1: str,
        address2: str,
        address3: str,
        address4: str,
        address5: str,
        locality: str,
        administrative_area: str,
        postal_code: str,
        country: str,
        output_language: str,
    ) -> Object:
        """
        Calls the GetAddressInfo SOAP API to retrieve validated and corrected international address information.

        Parameters:
            address1: Address line 1 of the international address.
            address2: Address line 2 of the international address. Optional.
            address3: Address line 3 of the international address. Optional.
            address4: Address line 4 of the international address. Optional.
            address5: Address line 5 of the international address. Optional.
            locality: The city, town, or municipality of the address. Required if postal code is not provided.
            administrative_area: The state, region, or province of the address. Required if postal code is not provided.
            postal_code: The postal code of the address. Required if locality and administrative area are not provided.
            country: The country name or ISO 3166-1 Alpha-2/Alpha-3 code.
            output_language: The language for service output (e.g., "ENGLISH", "BOTH", "LOCAL_ROMAN", "LOCAL").
            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.

        Returns:
            suds.sudsobject.Object: SOAP response containing validated address details or error.

        Raises:
            RuntimeError: If both primary and backup endpoints fail.
        """
        # Common kwargs for both calls
        call_kwargs = dict(
            Address1=address1,
            Address2=address2,
            Address3=address3,
            Address4=address4,
            Address5=address5,
            Locality=locality,
            AdministrativeArea=administrative_area,
            PostalCode=postal_code,
            Country=country,
            OutputLanguage=output_language,
            LicenseKey=self.license_key,
        )

        # Attempt primary
        try:
            client = Client(self._primary_wsdl, timeout=self.timeout)
            # Override endpoint URL if needed:
            # client.set_options(location=self._primary_wsdl.replace('?wsdl','/soap'))
            response = client.service.GetAddressInfo(**call_kwargs)

            # If response invalid or Error.TypeCode == "3", 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 Error.TypeCode=3")

            return response

        except (WebFault, ValueError, Exception) as primary_ex:
            # Attempt backup
            try:
                client = Client(self._backup_wsdl, timeout=self.timeout)
                response = client.service.GetAddressInfo(**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 Validation International NodeJS Code Snippet

var args = {Address1: 'Address1',
            Address2: 'Address2',
            Address3: 'Address3',
            Address4: 'Address4',
            Address5: 'Address5',
            Locality: 'Locality',
            AdministrativeArea: 'AdministrativeArea',
            PostalCode: 'PostalCode',
            Country: 'Country',
            OutputLanguage: 'OutputLanguage',
            LicenseKey: 'LicenseKey'};
soap.createClient(primaryUrl, function(err, client) {
      
    client.GetAddressInfo(args, function(err, result) {
        //This is where you will handle the service results. Your business logic will determine
        //how the validated information is used.
        //The exact output can be found in our documentation:
        //https://www.serviceobjects.com/docs/dots-address-validation-international/
        if(err != null || result == null)
        {
            //There was an error that occurred that wasn't part of the normal service response
            return;
        }
        else{
       import { soap } from 'strong-soap';

/**
 * <summary>
 * A class that provides functionality to call the ServiceObjects Address Validation International (AVI) SOAP service's GetAddressInfo endpoint,
 * retrieving validated and corrected international address information with fallback to a backup endpoint for reliability in live mode.
 * </summary>
 */
class GetAddressInfoSoap {
    /**
     * <summary>
     * Initializes a new instance of the GetAddressInfoSoap class with the provided input parameters,
     * setting up primary and backup WSDL URLs based on the live/trial mode.
     * </summary>
     * @param {string} Address1 - Address line 1 of the international address.
     * @param {string} Address2 - Address line 2 of the international address. Optional.
     * @param {string} Address3 - Address line 3 of the international address. Optional.
     * @param {string} Address4 - Address line 4 of the international address. Optional.
     * @param {string} Address5 - Address line 5 of the international address. Optional.
     * @param {string} Locality - The city, town, or municipality of the address. Required if postal code is not provided.
     * @param {string} AdministrativeArea - The state, region, or province of the address. Required if postal code is not provided.
     * @param {string} PostalCode - The postal code of the address. Required if locality and administrative area are not provided.
     * @param {string} Country - The country name or ISO 3166-1 Alpha-2/Alpha-3 code.
     * @param {string} OutputLanguage - The language for service output (e.g., "ENGLISH", "BOTH", "LOCAL_ROMAN", "LOCAL").
     * @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(Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, LicenseKey, isLive = true, timeoutSeconds = 15) {
        if (!LicenseKey) {
            throw new Error('LicenseKey cannot be empty or null.');
        }

        this.args = {
            Address1,
            Address2,
            Address3,
            Address4,
            Address5,
            Locality,
            AdministrativeArea,
            PostalCode,
            Country,
            OutputLanguage,
            LicenseKey
        };

        this.isLive = isLive;
        this.timeoutSeconds = timeoutSeconds;

        this.LiveBaseUrl = 'https://sws.serviceobjects.com/avi/soap.svc?wsdl';
        this.BackupBaseUrl = 'https://swsbackup.serviceobjects.com/avi/soap.svc?wsdl';
        this.TrialBaseUrl = 'https://trial.serviceobjects.com/avi/soap.svc?wsdl';

        this._primaryWsdl = this.isLive ? this.LiveBaseUrl : this.TrialBaseUrl;
        this._backupWsdl = this.isLive ? this.BackupBaseUrl : this.TrialBaseUrl;
    }

    /**
     * <summary>
     * Asynchronously calls the GetAddressInfo 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 an object 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 {
                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 GetAddressInfo 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.GetAddressInfo(args, (err, result) => {
                    const response = result?.GetAddressInfoResult;
                    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 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 { GetAddressInfoSoap };     //Check for an error object
            if(result.GetAddressInfoResult.Error != null)
            {
                //An error object was returned by the service and you will want to use
                //the following failover logic.
                //If it was a Service Objects Fatal exception we recommend trying
                //a backup server.
                if(result.GetAddressInfoResult.Error.TypeCode == "3")
                {
                    //The actual backup url will be provided when you purchase a license key
                    var backupUrl = 'https://trial.serviceobjects.com/avi/soap.svc?wsdl';
                    soap.createClient(backupUrl, function(failoverErr, backupClient) {
      
                        backupClient.GetAddressInfo(args, function(failoverErr, failoverResult) {
                            //Handle the failoverErr or failoverResult objects.
                            return;
                        });
                    });
                }
                else{
                    //The Error object isn't of the type "Service Objects Fatal" so
                    //there is no need to use the failover logic. There was some Error of
                    //type Authorization, User Input, or Domain Specific.
                    response.writeHead(200, "OK", {'Content-Type': 'text/html'});
                    response.end(JSON.stringify(result));
                    return;
                }
            }
            else{
                //You have a non Error response.
                //All of the data will reside within the result object
                //As an easy to see what the service returns I am returning a JSON
                //serialized version as the response.
                response.writeHead(200, "OK", {'Content-Type': 'text/html'});
                response.end(JSON.stringify(result));
                return;
            }
        }
        });
});