Address Validation Canada 2 C# Rest Code Snippet

namespace address_validation_canada_2_dot_net.REST
{
    /// <summary>
    /// Provides functionality to call the ServiceObjects AVCA2 REST API's ValidateCanadianAddressV2 endpoint,
    /// retrieving validated Canadian address information (e.g., corrected address, municipality, province, postal code)
    /// for a given input with fallback to a backup endpoint for reliability in live mode.
    /// </summary>
    public static class ValidateCanadianAddressV2Client
    {
        // Base URL constants: production, backup, and trial
        private const string LiveBaseUrl = "https://sws.serviceobjects.com/AVCA2/api.svc/";
        private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/AVCA2/api.svc/";
        private const string TrialBaseUrl = "https://trial.serviceobjects.com/AVCA2/api.svc/";

        /// <summary>
        /// Synchronously calls the ValidateCanadianAddressV2 REST endpoint to retrieve validated address information,
        /// attempting the primary endpoint first and falling back to the backup if the response is invalid
        /// (Error.TypeCode == "3") in live mode.
        /// </summary>
        /// <param name="input">The input parameters including address, municipality, province, postal code, language, and license key.</param>
        /// <returns>Deserialized <see cref="AVCA2Response"/> containing validated address data or an error.</returns>
        public static AVCA2Response Invoke(ValidateCanadianAddressV2Input input)
        {
            // Use query string parameters so missing/optional fields don't break the URL
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            AVCA2Response response = Helper.HttpGet<AVCA2Response>(url, input.TimeoutSeconds);

            // Fallback on error in live mode
            if (input.IsLive && !ValidResponse(response))
            {
                string fallbackUrl = BuildUrl(input, BackupBaseUrl);
                AVCA2Response fallbackResponse = Helper.HttpGet<AVCA2Response>(fallbackUrl, input.TimeoutSeconds);
                return fallbackResponse;
            }

            return response;
        }

        /// <summary>
        /// Asynchronously calls the ValidateCanadianAddressV2 REST endpoint to retrieve validated address information,
        /// attempting the primary endpoint first and falling back to the backup if the response is invalid
        /// (Error.TypeCode == "3") in live mode.
        /// </summary>
        /// <param name="input">The input parameters including address, municipality, province, postal code, language, and license key.</param>
        /// <returns>Deserialized <see cref="AVCA2Response"/> containing validated address data or an error.</returns>
        public static async Task<AVCA2Response> InvokeAsync(ValidateCanadianAddressV2Input input)
        {
            // Use query string parameters so missing/optional fields don't break the URL
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            AVCA2Response response = await Helper.HttpGetAsync<AVCA2Response>(url, input.TimeoutSeconds).ConfigureAwait(false);

            // Fallback on error in live mode
            if (input.IsLive && !ValidResponse(response))
            {
                string fallbackUrl = BuildUrl(input, BackupBaseUrl);
                AVCA2Response fallbackResponse = await Helper.HttpGetAsync<AVCA2Response>(fallbackUrl, input.TimeoutSeconds).ConfigureAwait(false);
                return fallbackResponse;
            }

            return response;
        }

        // Build the full request URL, including URL-encoded query string
        public static string BuildUrl(ValidateCanadianAddressV2Input input, string baseUrl)
        {
            // Construct query string with URL-encoded parameters
            string qs = $"ValidateCanadianAddressV2?" +
                        $"Address={Helper.UrlEncode(input.Address)}" +
                        $"&Address2={Helper.UrlEncode(input.Address2)}" +
                        $"&Municipality={Helper.UrlEncode(input.Municipality)}" +
                        $"&Province={Helper.UrlEncode(input.Province)}" +
                        $"&PostalCode={Helper.UrlEncode(input.PostalCode)}" +
                        $"&Language={Helper.UrlEncode(input.Language)}" +
                        $"&LicenseKey={Helper.UrlEncode(input.LicenseKey)}" +
                        $"&Format=JSON";
            return baseUrl + qs;
        }

        private static bool ValidResponse(AVCA2Response response) => response?.Error == null || response.Error.TypeCode != "3";

        /// <summary>
        /// Input parameters for the ValidateCanadianAddressV2 API call. Represents a Canadian address to validate.
        /// </summary>
        /// <param name="Address">Address line of the address to validate (e.g., "50 Coach Hill Dr").</param>
        /// <param name="Address2">Secondary address line. Optional.</param>
        /// <param name="Municipality">The municipality of the address (e.g., "Kitchener"). Optional if postal code is provided.</param>
        /// <param name="Province">The province of the address (e.g., "Ont"). Optional if postal code is provided.</param>
        /// <param name="PostalCode">The postal code of the address (e.g., "N2E 1P4"). Optional if municipality and province are provided.</param>
        /// <param name="Language">The language for the response (e.g., "EN", "FR", "EN-Proper"). Optional.</param>
        /// <param name="LicenseKey">The license key to authenticate the API request.</param>
        /// <param name="IsLive">Indicates whether to use the live service (true) or trial service (false).</param>
        /// <param name="TimeoutSeconds">Timeout duration for the API call, in seconds.</param>
        public record ValidateCanadianAddressV2Input(
            string Address = "",
            string Address2 = "",
            string Municipality = "",
            string Province = "",
            string PostalCode = "",
            string Language = "",
            string LicenseKey = "",
            bool IsLive = true,
            int TimeoutSeconds = 15
        );
    }
}


using System.Text.Json;
using System.Web;

namespace address_validation_canada_2_dot_net.REST
{
    public class Helper
    {
        public static T HttpGet<T>(string url, int timeoutSeconds)
        {
            using var httpClient = new HttpClient
            {
                Timeout = TimeSpan.FromSeconds(timeoutSeconds)
            };
            using var request = new HttpRequestMessage(HttpMethod.Get, url);
            using HttpResponseMessage response = httpClient
                .SendAsync(request)
                .GetAwaiter()
                .GetResult();
            response.EnsureSuccessStatusCode();
            using Stream responseStream = response.Content
                .ReadAsStreamAsync()
                .GetAwaiter()
                .GetResult();
            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };
            object? obj = JsonSerializer.Deserialize(responseStream, typeof(T), options);
            T result = (T)obj!;
            return result;
        }

        // Asynchronous HTTP GET and JSON deserialize
        public static async Task<T> HttpGetAsync<T>(string url, int timeoutSeconds)
        {
            HttpClient HttpClient = new HttpClient();
            HttpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
            using var httpResponse = await HttpClient.GetAsync(url).ConfigureAwait(false);
            httpResponse.EnsureSuccessStatusCode();
            var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
            return JsonSerializer.Deserialize<T>(stream)!;
        }

        public static string UrlEncode(string value) => HttpUtility.UrlEncode(value ?? string.Empty);
    }
}

Address Validation Canada 2 Python Code Snippet

from avca2_response import AVCA2Response, CanadianAddressInfoV2, Error
import requests

# Endpoint URLs for ServiceObjects AVCA2 (Address Validation - Canada) API
primary_url = "https://sws.serviceobjects.com/AVCA2/api.svc/ValidateCanadianAddressV2?"
backup_url = "https://swsbackup.serviceobjects.com/AVCA2/api.svc/ValidateCanadianAddressV2?"
trial_url = "https://trial.serviceobjects.com/AVCA2/api.svc/ValidateCanadianAddressV2?"

def validate_canadian_address_v2(
    address: str,
    address2: str,
    municipality: str,
    province: str,
    postal_code: str,
    language: str,
    license_key: str,
    is_live: bool,
    timeout_seconds: int = 15
) -> AVCA2Response:
    """
    Call ServiceObjects AVCA2 API's ValidateCanadianAddressV2 endpoint
    to retrieve validated Canadian address information for a given address.

    Parameters:
        address: Address line of the address to validate (e.g., "50 Coach Hill Dr").
        address2: Secondary address line (e.g., "Apt 4B"). Optional.
        municipality: The municipality of the address (e.g., "Kitchener"). Optional if postal code is provided.
        province: The province of the address (e.g., "Ont"). Optional if postal code is provided.
        postal_code: The postal code of the address (e.g., "N2E 1P4"). Optional if municipality and province are provided.
        language: The language for the response (e.g., "EN", "FR", "EN-Proper", "FR-Proper"). Optional.
        license_key: Your ServiceObjects license key.
        is_live: Use live or trial servers.
        timeout_seconds: Timeout for the HTTP request in seconds.

    Returns:
        AVCA2Response: Parsed JSON response with validated address details or error details.

    Raises:
        RuntimeError: If the API returns an error payload.
        requests.RequestException: On network/HTTP failures (trial mode).
    """
    params = {
        "Address": address,
        "Address2": address2,
        "Municipality": municipality,
        "Province": province,
        "PostalCode": postal_code,
        "Language": language,
        "LicenseKey": license_key,
        "Format":"JSON"
    }
    # Select the base URL: production vs trial
    url = primary_url if is_live else trial_url

    try:
        # Attempt primary (or trial) endpoint
        response = requests.get(url, params=params, timeout=timeout_seconds)
        response.raise_for_status()
        data = response.json()

        # If API returned an error in JSON payload, trigger fallback
        error = data.get('Error')
        if not (error is None or error.get('TypeCode') != "3"):
            if is_live:
                # Try backup URL
                response = requests.get(backup_url, params=params, timeout=timeout_seconds)
                response.raise_for_status()
                data = response.json()

                # If still error, propagate exception
                if 'Error' in data:
                    raise RuntimeError(f"AVCA2 service error: {data['Error']}")
            else:
                # Trial mode error is terminal
                raise RuntimeError(f"AVCA2 trial error: {data['Error']}")

        # Convert JSON response to AVCA2Response for structured access
        error = Error(**data.get("Error", {})) if data.get("Error") else None

        return AVCA2Response(
            CanadianAddressInfoV2=CanadianAddressInfoV2(
                Address=data.get("CanadianAddressInfoV2", {}).get("Address"),
                Address2=data.get("CanadianAddressInfoV2", {}).get("Address2"),
                Municipality=data.get("CanadianAddressInfoV2", {}).get("Municipality"),
                Province=data.get("CanadianAddressInfoV2", {}).get("Province"),
                PostalCode=data.get("CanadianAddressInfoV2", {}).get("PostalCode"),
                TimeZone=data.get("CanadianAddressInfoV2", {}).get("TimeZone"),
                AddressNumberFragment=data.get("CanadianAddressInfoV2", {}).get("AddressNumberFragment"),
                StreetNameFragment=data.get("CanadianAddressInfoV2", {}).get("StreetNameFragment"),
                StreetTypeFragment=data.get("CanadianAddressInfoV2", {}).get("StreetTypeFragment"),
                DirectionalCodeFragment=data.get("CanadianAddressInfoV2", {}).get("DirectionalCodeFragment"),
                UnitTypeFragment=data.get("CanadianAddressInfoV2", {}).get("UnitTypeFragment"),
                UnitNumberFragment=data.get("CanadianAddressInfoV2", {}).get("UnitNumberFragment"),
                IsPOBox=data.get("CanadianAddressInfoV2", {}).get("IsPOBox"),
                BoxNumberFragment=data.get("CanadianAddressInfoV2", {}).get("BoxNumberFragment"),
                StationInfo=data.get("CanadianAddressInfoV2", {}).get("StationInfo"),
                DeliveryMode=data.get("CanadianAddressInfoV2", {}).get("DeliveryMode"),
                DeliveryInstallation=data.get("CanadianAddressInfoV2", {}).get("DeliveryInstallation"),
                Corrections=data.get("CanadianAddressInfoV2", {}).get("Corrections"),
                CorrectionsDescriptions=data.get("CanadianAddressInfoV2", {}).get("CorrectionsDescriptions")
            ) if data.get("CanadianAddressInfoV2") else None,
            Error=error,
        )

    except requests.RequestException as req_exc:
        # Network or HTTP-level error occurred
        if is_live:
            try:
                # Fallback to backup URL
                response = requests.get(backup_url, params=params, timeout=timeout_seconds)
                response.raise_for_status()
                data = response.json()
                if "Error" in data:
                    raise RuntimeError(f"AVCA2 backup error: {data['Error']}") from req_exc

                error = Error(**data.get("Error", {})) if data.get("Error") else None

                return AVCA2Response(
                    CanadianAddressInfoV2=CanadianAddressInfoV2(
                        Address=data.get("CanadianAddressInfoV2", {}).get("Address"),
                        Address2=data.get("CanadianAddressInfoV2", {}).get("Address2"),
                        Municipality=data.get("CanadianAddressInfoV2", {}).get("Municipality"),
                        Province=data.get("CanadianAddressInfoV2", {}).get("Province"),
                        PostalCode=data.get("CanadianAddressInfoV2", {}).get("PostalCode"),
                        TimeZone=data.get("CanadianAddressInfoV2", {}).get("TimeZone"),
                        AddressNumberFragment=data.get("CanadianAddressInfoV2", {}).get("AddressNumberFragment"),
                        StreetNameFragment=data.get("CanadianAddressInfoV2", {}).get("StreetNameFragment"),
                        StreetTypeFragment=data.get("CanadianAddressInfoV2", {}).get("StreetTypeFragment"),
                        DirectionalCodeFragment=data.get("CanadianAddressInfoV2", {}).get("DirectionalCodeFragment"),
                        UnitTypeFragment=data.get("CanadianAddressInfoV2", {}).get("UnitTypeFragment"),
                        UnitNumberFragment=data.get("CanadianAddressInfoV2", {}).get("UnitNumberFragment"),
                        IsPOBox=data.get("CanadianAddressInfoV2", {}).get("IsPOBox"),
                        BoxNumberFragment=data.get("CanadianAddressInfoV2", {}).get("BoxNumberFragment"),
                        StationInfo=data.get("CanadianAddressInfoV2", {}).get("StationInfo"),
                        DeliveryMode=data.get("CanadianAddressInfoV2", {}).get("DeliveryMode"),
                        DeliveryInstallation=data.get("CanadianAddressInfoV2", {}).get("DeliveryInstallation"),
                        Corrections=data.get("CanadianAddressInfoV2", {}).get("Corrections"),
                        CorrectionsDescriptions=data.get("CanadianAddressInfoV2", {}).get("CorrectionsDescriptions")
                    ) if data.get("CanadianAddressInfoV2") else None,
                    Error=error,
                )
            except Exception as backup_exc:
                raise RuntimeError("AVCA2 service unreachable on both endpoints") from backup_exc
        else:
            raise RuntimeError(f"AVCA2 trial error: {str(req_exc)}") from req_exc




from dataclasses import dataclass
from typing import Optional, List

@dataclass
class Error:
    Type: Optional[str] = None
    TypeCode: Optional[str] = None
    Desc: Optional[str] = None
    DescCode: Optional[str] = None

    def __str__(self) -> str:
        return (f"Error: Type={self.Type}, TypeCode={self.TypeCode}, Desc={self.Desc}, "
                f"DescCode={self.DescCode}")

@dataclass
class CanadianAddressInfo:
    Address: Optional[str] = None
    Address2: Optional[str] = None
    Municipality: Optional[str] = None
    Province: Optional[str] = None
    PostalCode: Optional[str] = None
    TimeZone: Optional[str] = None
    AddressNumberFragment: Optional[str] = None
    StreetNameFragment: Optional[str] = None
    StreetTypeFragment: Optional[str] = None
    DirectionalCodeFragment: Optional[str] = None
    UnitTypeFragment: Optional[str] = None
    UnitNumberFragment: Optional[str] = None
    IsPOBox: Optional[bool] = None
    BoxNumberFragment: Optional[str] = None
    StationInfo: Optional[str] = None
    DeliveryMode: Optional[str] = None
    DeliveryInstallation: Optional[str] = None

    def __str__(self) -> str:
        return (f"CanadianAddressInfo: Address={self.Address}, Address2={self.Address2}, "
                f"Municipality={self.Municipality}, Province={self.Province}, PostalCode={self.PostalCode}, "
                f"TimeZone={self.TimeZone}, AddressNumberFragment={self.AddressNumberFragment}, "
                f"StreetNameFragment={self.StreetNameFragment}, StreetTypeFragment={self.StreetTypeFragment}, "
                f"DirectionalCodeFragment={self.DirectionalCodeFragment}, UnitTypeFragment={self.UnitTypeFragment}, "
                f"UnitNumberFragment={self.UnitNumberFragment}, IsPOBox={self.IsPOBox}, "
                f"BoxNumberFragment={self.BoxNumberFragment}, StationInfo={self.StationInfo}, "
                f"DeliveryMode={self.DeliveryMode}, DeliveryInstallation={self.DeliveryInstallation}")

@dataclass
class CanadianAddressInfoV2:
    Address: Optional[str] = None
    Address2: Optional[str] = None
    Municipality: Optional[str] = None
    Province: Optional[str] = None
    PostalCode: Optional[str] = None
    TimeZone: Optional[str] = None
    AddressNumberFragment: Optional[str] = None
    StreetNameFragment: Optional[str] = None
    StreetTypeFragment: Optional[str] = None
    DirectionalCodeFragment: Optional[str] = None
    UnitTypeFragment: Optional[str] = None
    UnitNumberFragment: Optional[str] = None
    IsPOBox: Optional[bool] = None
    BoxNumberFragment: Optional[str] = None
    StationInfo: Optional[str] = None
    DeliveryMode: Optional[str] = None
    DeliveryInstallation: Optional[str] = None
    Corrections: Optional[str] = None
    CorrectionsDescriptions: Optional[str] = None

    def __str__(self) -> str:
        return (f"CanadianAddressInfoV2: Address={self.Address}, Address2={self.Address2}, "
                f"Municipality={self.Municipality}, Province={self.Province}, PostalCode={self.PostalCode}, "
                f"TimeZone={self.TimeZone}, AddressNumberFragment={self.AddressNumberFragment}, "
                f"StreetNameFragment={self.StreetNameFragment}, StreetTypeFragment={self.StreetTypeFragment}, "
                f"DirectionalCodeFragment={self.DirectionalCodeFragment}, UnitTypeFragment={self.UnitTypeFragment}, "
                f"UnitNumberFragment={self.UnitNumberFragment}, IsPOBox={self.IsPOBox}, "
                f"BoxNumberFragment={self.BoxNumberFragment}, StationInfo={self.StationInfo}, "
                f"DeliveryMode={self.DeliveryMode}, DeliveryInstallation={self.DeliveryInstallation}, "
                f"Corrections={self.Corrections}, CorrectionsDescriptions={self.CorrectionsDescriptions}")

@dataclass
class AVCA2Response:
    CanadianAddressInfoV2: Optional['CanadianAddressInfoV2'] = None
    CanadianAddressInfo: Optional['CanadianAddressInfo'] = None
    Error: Optional['Error'] = None

    def __str__(self) -> str:
        address_info_v2 = str(self.CanadianAddressInfoV2) if self.CanadianAddressInfoV2 else 'None'
        address_info = str(self.CanadianAddressInfo) if self.CanadianAddressInfo else 'None'
        error = str(self.Error) if self.Error else 'None'
        return (f"AVCA2Response: CanadianAddressInfoV2={address_info_v2}, "
                f"CanadianAddressInfo={address_info}, Error={error}]")

Address Validation Canada 2 REST NodeJS Code Snippet

import axios from 'axios';
import querystring from 'querystring';
import { AVCA2Response } from './avca2_response.js';

/**
 * @constant
 * @type {string}
 * @description The base URL for the live ServiceObjects AVCA2 (Address Validation - Canada) API service.
 */
const LiveBaseUrl = 'https://sws.serviceobjects.com/AVCA2/api.svc/';

/**
 * @constant
 * @type {string}
 * @description The base URL for the backup ServiceObjects AVCA2 API service.
 */
const BackupBaseUrl = 'https://swsbackup.serviceobjects.com/AVCA2/api.svc/';

/**
 * @constant
 * @type {string}
 * @description The base URL for the trial ServiceObjects AVCA2 API service.
 */
const TrialBaseUrl = 'https://trial.serviceobjects.com/AVCA2/api.svc/';

/**
 * @summary
 * Checks if a response from the API is valid by verifying that it either has no Error object
 * or the Error.TypeCode is not equal to '3'.
 * @param {Object} response - The API response object to validate.
 * @returns {boolean} True if the response is valid, false otherwise.
 */
const isValid = (response) => !response?.Error || response.Error.TypeCode !== '3';

/**
 * @summary
 * Constructs a full URL for the ValidateCanadianAddressV2 API endpoint by combining the base URL
 * with query parameters derived from the input parameters.
 * @param {Object} params - An object containing all the input parameters.
 * @param {string} baseUrl - The base URL for the API service (live, backup, or trial).
 * @returns {string} The constructed URL with query parameters.
 */
const buildUrl = (params, baseUrl) =>
    `${baseUrl}ValidateCanadianAddressV2?${querystring.stringify(params)}`;

/**
 * @summary
 * Performs an HTTP GET request to the specified URL with a given timeout.
 * @param {string} url - The URL to send the GET request to.
 * @param {number} timeoutSeconds - The timeout duration in seconds for the request.
 * @returns {Promise<AVCA2Response>} A promise that resolves to an AVCA2Response object containing the API response data.
 * @throws {Error} Thrown if the HTTP request fails, with a message detailing the error.
 */
const httpGet = async (url, timeoutSeconds) => {
    try {
        const response = await axios.get(url, { timeout: timeoutSeconds * 1000 });
        return new AVCA2Response(response.data);
    } catch (error) {
        throw new Error(`HTTP request failed: ${error.message}`);
    }
};

/**
 * @summary
 * Provides functionality to call the ServiceObjects AVCA2 API's ValidateCanadianAddressV2 endpoint,
 * retrieving validated Canadian address information with fallback to a backup endpoint for reliability in live mode.
 */
const ValidateCanadianAddressV2Client = {
    /**
     * @summary
     * Asynchronously invokes the ValidateCanadianAddressV2 API endpoint, attempting the primary endpoint
     * first and falling back to the backup if the response is invalid (Error.TypeCode == '3') in live mode.
     * @param {string} Address - Address line of the address to validate (e.g., "50 Coach Hill Dr").
     * @param {string} Address2 - Secondary address line (e.g., "Apt 4B"). Optional.
     * @param {string} Municipality - The municipality of the address (e.g., "Kitchener"). Optional if postal code is provided.
     * @param {string} Province - The province of the address (e.g., "Ont"). Optional if postal code is provided.
     * @param {string} PostalCode - The postal code of the address (e.g., "N2E 1P4"). Optional if municipality and province are provided.
     * @param {string} Language - The language for the response (e.g., "EN", "FR", "EN-Proper", "FR-Proper"). Optional.
     * @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.
     * @returns {Promise<AVCA2Response>} A promise that resolves to an AVCA2Response object.
     */
    async invokeAsync(Address, Address2, Municipality, Province, PostalCode, Language, LicenseKey, isLive = true, timeoutSeconds = 15) {
        const params = {
            Address,
            Address2,
            Municipality,
            Province,
            PostalCode,
            Language,
            LicenseKey,
            Format: 'JSON'
        };

        const url = buildUrl(params, isLive ? LiveBaseUrl : TrialBaseUrl);
        let response = await httpGet(url, timeoutSeconds);

        if (isLive && !isValid(response)) {
            const fallbackUrl = buildUrl(params, BackupBaseUrl);
            const fallbackResponse = await httpGet(fallbackUrl, timeoutSeconds);
            return fallbackResponse;
        }
        return response;
    },

    /**
     * @summary
     * Synchronously invokes the ValidateCanadianAddressV2 API endpoint by wrapping the async call
     * and awaiting its result immediately.
     * @param {string} Address - Address line of the address to validate (e.g., "50 Coach Hill Dr").
     * @param {string} Address2 - Secondary address line (e.g., "Apt 4B"). Optional.
     * @param {string} Municipality - The municipality of the address (e.g., "Kitchener"). Optional if postal code is provided.
     * @param {string} Province - The province of the address (e.g., "Ont"). Optional if postal code is provided.
     * @param {string} PostalCode - The postal code of the address (e.g., "N2E 1P4"). Optional if municipality and province are provided.
     * @param {string} Language - The language for the response (e.g., "EN", "FR", "EN-Proper", "FR-Proper"). Optional.
     * @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.
     * @returns {AVCA2Response} An AVCA2Response object with validated address details or an error.
     */
    invoke(Address, Address2, Municipality, Province, PostalCode, Language, LicenseKey, isLive = true, timeoutSeconds = 15) {
        return (async () => await this.invokeAsync(
            Address, Address2, Municipality, Province, PostalCode, Language, LicenseKey, isLive, timeoutSeconds
        ))();
    }
};

export { ValidateCanadianAddressV2Client, AVCA2Response };


export class AVCA2Response {
    constructor(data = {}) {
        this.CanadianAddressInfoV2 = data.CanadianAddressInfoV2 ? new CanadianAddressInfoV2(data.CanadianAddressInfoV2) : null;
        this.CanadianAddressInfo = data.CanadianAddressInfo ? new CanadianAddressInfo(data.CanadianAddressInfo) : null;
        this.Error = data.Error ? new Error(data.Error) : null;
        this.Debug = data.Debug || [];
    }

    toString() {
        const debugString = this.Debug.length ? this.Debug.join(', ') : 'null';
        return `AVCA2Response: CanadianAddressInfoV2 = ${this.CanadianAddressInfoV2 ? this.CanadianAddressInfoV2.toString() : 'null'}, CanadianAddressInfo = ${this.CanadianAddressInfo ? this.CanadianAddressInfo.toString() : 'null'}, Error = ${this.Error ? this.Error.toString() : 'null'}, Debug = [${debugString}]`;
    }
}

export class CanadianAddressInfoV2 {
    constructor(data = {}) {
        this.Address = data.Address;
        this.Address2 = data.Address2;
        this.Municipality = data.Municipality;
        this.Province = data.Province;
        this.PostalCode = data.PostalCode;
        this.TimeZone = data.TimeZone;
        this.AddressNumberFragment = data.AddressNumberFragment;
        this.StreetNameFragment = data.StreetNameFragment;
        this.StreetTypeFragment = data.StreetTypeFragment;
        this.DirectionalCodeFragment = data.DirectionalCodeFragment;
        this.UnitTypeFragment = data.UnitTypeFragment;
        this.UnitNumberFragment = data.UnitNumberFragment;
        this.IsPOBox = data.IsPOBox;
        this.BoxNumberFragment = data.BoxNumberFragment;
        this.StationInfo = data.StationInfo;
        this.DeliveryMode = data.DeliveryMode;
        this.DeliveryInstallation = data.DeliveryInstallation;
        this.Corrections = data.Corrections;
        this.CorrectionsDescriptions = data.CorrectionsDescriptions;
    }

    toString() {
        return `CanadianAddressInfoV2: Address = ${this.Address}, Address2 = ${this.Address2}, Municipality = ${this.Municipality}, Province = ${this.Province}, PostalCode = ${this.PostalCode}, TimeZone = ${this.TimeZone}, AddressNumberFragment = ${this.AddressNumberFragment}, StreetNameFragment = ${this.StreetNameFragment}, StreetTypeFragment = ${this.StreetTypeFragment}, DirectionalCodeFragment = ${this.DirectionalCodeFragment}, UnitTypeFragment = ${this.UnitTypeFragment}, UnitNumberFragment = ${this.UnitNumberFragment}, IsPOBox = ${this.IsPOBox}, BoxNumberFragment = ${this.BoxNumberFragment}, StationInfo = ${this.StationInfo}, DeliveryMode = ${this.DeliveryMode}, DeliveryInstallation = ${this.DeliveryInstallation}, Corrections = ${this.Corrections}, CorrectionsDescriptions = ${this.CorrectionsDescriptions}`;
    }
}

export class Error {
    constructor(data = {}) {
        this.Type = data.Type;
        this.TypeCode = data.TypeCode;
        this.Desc = data.Desc;
        this.DescCode = data.DescCode;
    }

    toString() {
        return `Error: Type = ${this.Type}, TypeCode = ${this.TypeCode}, Desc = ${this.Desc}, DescCode = ${this.DescCode}`;
    }
}
export class CanadianAddressInfo {
    constructor(data = {}) {
        this.Address = data.Address;
        this.Address2 = data.Address2;
        this.Municipality = data.Municipality;
        this.Province = data.Province;
        this.PostalCode = data.PostalCode;
        this.TimeZone = data.TimeZone;
        this.AddressNumberFragment = data.AddressNumberFragment;
        this.StreetNameFragment = data.StreetNameFragment;
        this.StreetTypeFragment = data.StreetTypeFragment;
        this.DirectionalCodeFragment = data.DirectionalCodeFragment;
        this.UnitTypeFragment = data.UnitTypeFragment;
        this.UnitNumberFragment = data.UnitNumberFragment;
        this.IsPOBox = data.IsPOBox;
        this.BoxNumberFragment = data.BoxNumberFragment;
        this.StationInfo = data.StationInfo;
        this.DeliveryMode = data.DeliveryMode;
        this.DeliveryInstallation = data.DeliveryInstallation;
    }

    toString() {
        return `CanadianAddressInfo: Address = ${this.Address}, Address2 = ${this.Address2}, Municipality = ${this.Municipality}, Province = ${this.Province}, PostalCode = ${this.PostalCode}, TimeZone = ${this.TimeZone}, AddressNumberFragment = ${this.AddressNumberFragment}, StreetNameFragment = ${this.StreetNameFragment}, StreetTypeFragment = ${this.StreetTypeFragment}, DirectionalCodeFragment = ${this.DirectionalCodeFragment}, UnitTypeFragment = ${this.UnitTypeFragment}, UnitNumberFragment = ${this.UnitNumberFragment}, IsPOBox = ${this.IsPOBox}, BoxNumberFragment = ${this.BoxNumberFragment}, StationInfo = ${this.StationInfo}, DeliveryMode = ${this.DeliveryMode}, DeliveryInstallation = ${this.DeliveryInstallation}`;
    }
}

export default AVCA2Response;