Address Validation International C# Rest Code Snippet

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

        /// <summary>
        /// Synchronously calls the GetAddressInfo REST endpoint to retrieve validated international 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 lines, locality, administrative area, postal code, country, output language, and license key.</param>
        /// <returns>Deserialized <see cref="AddressInfoResponse"/> containing validated address data or an error.</returns>
        public static AddressInfoResponse Invoke(GetAddressInfoInput input)
        {
            // Use query string parameters so missing/optional fields don't break the URL
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            AddressInfoResponse response = Helper.HttpGet<AddressInfoResponse>(url, input.TimeoutSeconds);

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

            return response;
        }

        /// <summary>
        /// Asynchronously calls the GetAddressInfo REST endpoint to retrieve validated international 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 lines, locality, administrative area, postal code, country, output language, and license key.</param>
        /// <returns>Deserialized <see cref="AddressInfoResponse"/> containing validated address data or an error.</returns>
        public static async Task<AddressInfoResponse> InvokeAsync(GetAddressInfoInput input)
        {
            // Use query string parameters so missing/optional fields don't break the URL
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            AddressInfoResponse response = await Helper.HttpGetAsync<AddressInfoResponse>(url, input.TimeoutSeconds).ConfigureAwait(false);

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

            return response;
        }

        // Build the full request URL, including URL-encoded query string
        public static string BuildUrl(GetAddressInfoInput input, string baseUrl)
        {
            // Construct query string with URL-encoded parameters
            string qs = $"GetAddressInfo?" +
                        $"Address1={Helper.UrlEncode(input.Address1)}" +
                        $"&Address2={Helper.UrlEncode(input.Address2)}" +
                        $"&Address3={Helper.UrlEncode(input.Address3)}" +
                        $"&Address4={Helper.UrlEncode(input.Address4)}" +
                        $"&Address5={Helper.UrlEncode(input.Address5)}" +
                        $"&Locality={Helper.UrlEncode(input.Locality)}" +
                        $"&AdministrativeArea={Helper.UrlEncode(input.AdministrativeArea)}" +
                        $"&PostalCode={Helper.UrlEncode(input.PostalCode)}" +
                        $"&Country={Helper.UrlEncode(input.Country)}" +
                        $"&OutputLanguage={Helper.UrlEncode(input.OutputLanguage)}" +
                        $"&LicenseKey={Helper.UrlEncode(input.LicenseKey)}";
            return baseUrl + qs;
        }

        /// <summary>
        /// Validates the API response to determine if it is successful or requires a fallback.
        /// </summary>
        /// <param name="response">The API response to validate.</param>
        /// <returns>True if the response is valid (no error or TypeCode != "3"), false otherwise.</returns>
        private static bool ValidResponse(AddressInfoResponse response)
        {
            return response?.Error == null || response.Error.TypeCode != "3";
        }

        /// <summary>
        /// Input parameters for the GetAddressInfo API call. Represents an international address to validate and correct.
        /// </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>
        /// <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 GetAddressInfoInput(
            string Address1 = "",
            string Address2 = "",
            string Address3 = "",
            string Address4 = "",
            string Address5 = "",
            string Locality = "",
            string AdministrativeArea = "",
            string PostalCode = "",
            string Country = "",
            string OutputLanguage = "",
            string LicenseKey = "",
            bool IsLive = true,
            int TimeoutSeconds = 15
        );
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace address_validation_international_dot_net.REST
{/// <summary>
 /// Response from the AVI API
 /// </summary>
    public class AddressInfoResponse 
    {
        public AddressInfo AddressInfo { get; set; }
        public Error Error { get; set; }
        public override string ToString()
        {
            return $"AVI Response: " +
                $"\nAddressInfo: {AddressInfo} " +
                $"\nError: {{{Error}}}";
        }
    }
    /// <summary>
    /// Information on each address
    /// </summary>
    public class AddressInfo
    {
        public string Status { get; set; }
        public string ResolutionLevel { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string Address3 { get; set; }
        public string Address4 { get; set; }
        public string Address5 { get; set; }
        public string Address6 { get; set; }
        public string Address7 { get; set; }
        public string Address8 { get; set; }
        public string Locality { get; set; }
        public string AdministrativeArea { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public string CountryISO2 { get; set; }
        public string CountryISO3 { get; set; }
        public InformationComponent[] InformationComponents { get; set; }
        public override string ToString()
        {
            return $"\n{{Status: {Status} " +
                $"\nResolutionLevel: {ResolutionLevel} " +
                $"\nAddress1: {Address1} " +
                $"\nAddress2: {Address2} " +
                $"\nAddress2: {Address3} " +
                $"\nAddress4: {Address4} " +
                $"\nAddress5: {Address5} " +
                $"\nAddress6: {Address6} " +
                $"\nAddress7: {Address7} " +
                $"\nAddress8: {Address8} " +
                $"\nLocality: {Locality} " +
                $"\nAdministrativeArea: {AdministrativeArea} " +
                $"\nPostalCode: {PostalCode} " +
                $"\nCountry: {Country} " +
                $"\nCountryISO2: {CountryISO2} " +
                $"\nCountryISO3: {CountryISO3} " +
                $"\nInformationComponents: {InformationComponents}}}\n";
        }

    }
    public class InformationComponent
    {
        public string Name { get; set; }
        public string Value { get; set; }
        public override string ToString()
        {
            return $"Name: {Name} " +
                $"\nValue: {Value}\n";
        }
    }

    public class Error
    {
        public string Type { get; set; }
        public string TypeCode { get; set; }
        public string Desc { get; set; }
        public string DescCode { get; set; }
        public override string ToString()
        {
            return $"Type: {Type} " +
                $"\nTypeCode: {TypeCode} " +
                $"\nDesc: {Desc} " +
                $"\nDescCode: {DescCode} ";
        }
    }

}


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

namespace address_validation_international_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 International Python Code Snippet

from avi_response import AddressInfoResponse, AddressInfo, InformationComponent, Error
import requests

# Endpoint URLs for ServiceObjects Address Validation International (AVI) API
primary_url = "https://sws.serviceobjects.com/avi/api.svc/json/GetAddressInfo?"
backup_url = "https://swsbackup.serviceobjects.com/avi/api.svc/json/GetAddressInfo?"
trial_url = "https://trial.serviceobjects.com/avi/api.svc/json/GetAddressInfo?"

def get_address_info(
    address1: str,
    address2: str,
    address3: str,
    address4: str,
    address5: str,
    locality: str,
    administrative_area: str,
    postal_code: str,
    country: str,
    output_language: str,
    license_key: str,
    is_live: bool = True
) -> AddressInfoResponse:
    """
    Call ServiceObjects Address Validation International (AVI) API's GetAddressInfo endpoint
    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: Use live or trial servers.

    Returns:
        AddressInfoResponse: 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 = {
        "Address1": address1,
        "Address2": address2,
        "Address3": address3,
        "Address4": address4,
        "Address5": address5,
        "Locality": locality,
        "AdministrativeArea": administrative_area,
        "PostalCode": postal_code,
        "Country": country,
        "OutputLanguage": output_language,
        "LicenseKey": license_key,
    }
    # 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=10)
        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=10)
                response.raise_for_status()
                data = response.json()

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

        # Convert JSON response to AddressInfoResponse for structured access
        error = Error(**data.get("Error", {})) if data.get("Error") else None
        address_info = data.get("AddressInfo")
        address_info_obj = None
        if address_info:
            address_info_obj = AddressInfo(
                Status=address_info.get("Status"),
                ResolutionLevel=address_info.get("ResolutionLevel"),
                Address1=address_info.get("Address1"),
                Address2=address_info.get("Address2"),
                Address3=address_info.get("Address3"),
                Address4=address_info.get("Address4"),
                Address5=address_info.get("Address5"),
                Address6=address_info.get("Address6"),
                Address7=address_info.get("Address7"),
                Address8=address_info.get("Address8"),
                Locality=address_info.get("Locality"),
                AdministrativeArea=address_info.get("AdministrativeArea"),
                PostalCode=address_info.get("PostalCode"),
                Country=address_info.get("Country"),
                CountryISO2=address_info.get("CountryISO2"),
                CountryISO3=address_info.get("CountryISO3"),
                InformationComponents=[
                    InformationComponent(Name=comp.get("Name"), Value=comp.get("Value"))
                    for comp in address_info.get("InformationComponents", [])
                ] if "InformationComponents" in address_info else []
            )

        return AddressInfoResponse(
            AddressInfo=address_info_obj,
            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=10)
                response.raise_for_status()
                data = response.json()
                if "Error" in data:
                    raise RuntimeError(f"AVI backup error: {data['Error']}") from req_exc

                error = Error(**data.get("Error", {})) if data.get("Error") else None
                address_info = data.get("AddressInfo")
                address_info_obj = None
                if address_info:
                    address_info_obj = AddressInfo(
                        Status=address_info.get("Status"),
                        ResolutionLevel=address_info.get("ResolutionLevel"),
                        Address1=address_info.get("Address1"),
                        Address2=address_info.get("Address2"),
                        Address3=address_info.get("Address3"),
                        Address4=address_info.get("Address4"),
                        Address5=address_info.get("Address5"),
                        Address6=address_info.get("Address6"),
                        Address7=address_info.get("Address7"),
                        Address8=address_info.get("Address8"),
                        Locality=address_info.get("Locality"),
                        AdministrativeArea=address_info.get("AdministrativeArea"),
                        PostalCode=address_info.get("PostalCode"),
                        Country=address_info.get("Country"),
                        CountryISO2=address_info.get("CountryISO2"),
                        CountryISO3=address_info.get("CountryISO3"),
                        InformationComponents=[
                            InformationComponent(Name=comp.get("Name"), Value=comp.get("Value"))
                            for comp in address_info.get("InformationComponents", [])
                        ] if "InformationComponents" in address_info else []
                    )

                return AddressInfoResponse(
                    AddressInfo=address_info_obj,
                    Error=error
                )
            except Exception as backup_exc:
                raise RuntimeError("AVI service unreachable on both endpoints") from backup_exc
        else:
            raise RuntimeError(f"AVI trial error: {str(req_exc)}") from req_exc



from dataclasses import dataclass
from typing import Optional, List


@dataclass
class GetAddressInfoInput:
    Address1: Optional[str] = None
    Address2: Optional[str] = None
    Address3: Optional[str] = None
    Address4: Optional[str] = None
    Address5: Optional[str] = None
    Locality: Optional[str] = None
    AdministrativeArea: Optional[str] = None
    PostalCode: Optional[str] = None
    Country: Optional[str] = None
    OutputLanguage: str = "ENGLISH"
    LicenseKey: Optional[str] = None
    IsLive: bool = True
    TimeoutSeconds: int = 15

    def __str__(self) -> str:
        return (f"GetAddressInfoInput: Address1={self.Address1}, Address2={self.Address2}, Address3={self.Address3}, "
                f"Address4={self.Address4}, Address5={self.Address5}, Locality={self.Locality}, "
                f"AdministrativeArea={self.AdministrativeArea}, PostalCode={self.PostalCode}, "
                f"Country={self.Country}, OutputLanguage={self.OutputLanguage}, LicenseKey={self.LicenseKey}, "
                f"IsLive={self.IsLive}, TimeoutSeconds={self.TimeoutSeconds}")


@dataclass
class InformationComponent:
    Name: Optional[str] = None
    Value: Optional[str] = None

    def __str__(self) -> str:
        return f"InformationComponent: Name={self.Name}, Value={self.Value}"


@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}, DescCode={self.DescCode}"


@dataclass
class AddressInfo:
    Status: Optional[str] = None
    ResolutionLevel: Optional[str] = None
    Address1: Optional[str] = None
    Address2: Optional[str] = None
    Address3: Optional[str] = None
    Address4: Optional[str] = None
    Address5: Optional[str] = None
    Address6: Optional[str] = None
    Address7: Optional[str] = None
    Address8: Optional[str] = None
    Locality: Optional[str] = None
    AdministrativeArea: Optional[str] = None
    PostalCode: Optional[str] = None
    Country: Optional[str] = None
    CountryISO2: Optional[str] = None
    CountryISO3: Optional[str] = None
    InformationComponents: Optional[List['InformationComponent']] = None

    def __post_init__(self):
        if self.InformationComponents is None:
            self.InformationComponents = []

    def __str__(self) -> str:
        components_string = ', '.join(str(component) for component in self.InformationComponents) if self.InformationComponents else 'None'
        return (f"AddressInfo: Status={self.Status}, ResolutionLevel={self.ResolutionLevel}, "
                f"Address1={self.Address1}, Address2={self.Address2}, Address3={self.Address3}, "
                f"Address4={self.Address4}, Address5={self.Address5}, Address6={self.Address6}, "
                f"Address7={self.Address7}, Address8={self.Address8}, Locality={self.Locality}, "
                f"AdministrativeArea={self.AdministrativeArea}, PostalCode={self.PostalCode}, "
                f"Country={self.Country}, CountryISO2={self.CountryISO2}, CountryISO3={self.CountryISO3}, "
                f"InformationComponents=[{components_string}]")


@dataclass
class AddressInfoResponse:
    AddressInfo: Optional['AddressInfo'] = None
    Error: Optional['Error'] = None

    def __str__(self) -> str:
        address_info_string = str(self.AddressInfo) if self.AddressInfo else 'None'
        error_string = str(self.Error) if self.Error else 'None'
        return (f"AddressInfoResponse: AddressInfo={address_info_string}, "
                f"Error={error_string}]")

Address Validation International NodeJS REST Code Snippet

import axios from 'axios';
import querystring from 'querystring';
import { AddressInfoResponse } from './avi_response.js';

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

/**
 * @constant
 * @type {string}
 * @description The base URL for the backup ServiceObjects Address Validation International (AVI) API service.
 */
const BackupBaseUrl = 'https://swsbackup.serviceobjects.com/avi/api.svc/json/';

/**
 * @constant
 * @type {string}
 * @description The base URL for the trial ServiceObjects Address Validation International (AVI) API service.
 */
const TrialBaseUrl = 'https://trial.serviceobjects.com/avi/api.svc/json/';

/**
 * <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'.
 * </summary>
 * <param name="response" type="Object">The API response object to validate.</param>
 * <returns type="boolean">True if the response is valid, false otherwise.</returns>
 */
const isValid = (response) => !response?.Error || response.Error.TypeCode !== '3';

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

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

/**
 * <summary>
 * Provides functionality to call the ServiceObjects Address Validation International (AVI) API's GetAddressInfo endpoint,
 * retrieving validated and corrected international address information with fallback to a backup endpoint for reliability in live mode.
 * </summary>
 */
const GetAddressInfoClient = {
    /**
     * <summary>
     * Asynchronously invokes the GetAddressInfo API endpoint, attempting the primary endpoint
     * first and falling back to the backup if the response is invalid (Error.TypeCode == '3') in live 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.
     * @returns {Promise<AddressInfoResponse>} - A promise that resolves to an AddressInfoResponse object.
     */
    async invokeAsync(Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, LicenseKey, isLive = true, timeoutSeconds = 15) {
        const params = {
            Address1,
            Address2,
            Address3,
            Address4,
            Address5,
            Locality,
            AdministrativeArea,
            PostalCode,
            Country,
            OutputLanguage,
            LicenseKey
        };

        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 GetAddressInfo API endpoint by wrapping the async call
     * and awaiting its result immediately.
     * </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.
     * @returns {AddressInfoResponse} - An AddressInfoResponse object with validated address details or an error.
     */
    invoke(Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, LicenseKey, isLive = true, timeoutSeconds = 15) {
        return (async () => await this.invokeAsync(
            Address1, Address2, Address3, Address4, Address5, Locality, AdministrativeArea, PostalCode, Country, OutputLanguage, LicenseKey, isLive, timeoutSeconds
        ))();
    }
};

export { GetAddressInfoClient, AddressInfoResponse };


/**
 * Input parameters for the GetAddressInfo API call.
 */
export class GetAddressInfoInput {
    constructor(data = {}) {
        this.Address1 = data.Address1;
        this.Address2 = data.Address2;
        this.Address3 = data.Address3;
        this.Address4 = data.Address4;
        this.Address5 = data.Address5;
        this.Locality = data.Locality;
        this.AdministrativeArea = data.AdministrativeArea;
        this.PostalCode = data.PostalCode;
        this.Country = data.Country;
        this.OutputLanguage = data.OutputLanguage || 'ENGLISH';
        this.LicenseKey = data.LicenseKey;
        this.IsLive = data.IsLive !== undefined ? data.IsLive : true;
        this.TimeoutSeconds = data.TimeoutSeconds !== undefined ? data.TimeoutSeconds : 15;
    }

    toString() {
        return `GetAddressInfoInput: Address1 = ${this.Address1}, Address2 = ${this.Address2}, Address3 = ${this.Address3}, Address4 = ${this.Address4}, Address5 = ${this.Address5}, Locality = ${this.Locality}, AdministrativeArea = ${this.AdministrativeArea}, PostalCode = ${this.PostalCode}, Country = ${this.Country}, OutputLanguage = ${this.OutputLanguage}, LicenseKey = ${this.LicenseKey}, IsLive = ${this.IsLive}, TimeoutSeconds = ${this.TimeoutSeconds}`;
    }
}

/**
 * Information Component for API responses.
 */
export class InformationComponent {
    constructor(data = {}) {
        this.Name = data.Name;
        this.Value = data.Value;
    }

    toString() {
        return `Name = ${this.Name}, Value = ${this.Value}`;
    }
}

/**
 * Error object for API responses.
 */
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}`;
    }
}

/**
 * Address information for a validated international address.
 */
export class AddressInfo {
    constructor(data = {}) {
        this.Status = data.Status;
        this.ResolutionLevel = data.ResolutionLevel;
        this.Address1 = data.Address1;
        this.Address2 = data.Address2;
        this.Address3 = data.Address3;
        this.Address4 = data.Address4;
        this.Address5 = data.Address5;
        this.Address6 = data.Address6;
        this.Address7 = data.Address7;
        this.Address8 = data.Address8;
        this.Locality = data.Locality;
        this.AdministrativeArea = data.AdministrativeArea;
        this.PostalCode = data.PostalCode;
        this.Country = data.Country;
        this.CountryISO2 = data.CountryISO2;
        this.CountryISO3 = data.CountryISO3;
        this.InformationComponents = (data.InformationComponents || []).map(component => new InformationComponent(component));
    }

    toString() {
        const componentsString = this.InformationComponents.length
            ? this.InformationComponents.map(component => component.toString()).join(', ')
            : 'null';
        return `AddressInfo: Status = ${this.Status}, ResolutionLevel = ${this.ResolutionLevel}, Address1 = ${this.Address1}, Address2 = ${this.Address2}, Address3 = ${this.Address3}, Address4 = ${this.Address4}, Address5 = ${this.Address5}, Address6 = ${this.Address6}, Address7 = ${this.Address7}, Address8 = ${this.Address8}, Locality = ${this.Locality}, AdministrativeArea = ${this.AdministrativeArea}, PostalCode = ${this.PostalCode}, Country = ${this.Country}, CountryISO2 = ${this.CountryISO2}, CountryISO3 = ${this.CountryISO3}, InformationComponents = [${componentsString}]`;
    }
}

/**
 * Response from GetAddressInfo API, containing validated address information.
 */
export class AddressInfoResponse {
    constructor(data = {}) {
        this.AddressInfo = data.AddressInfo ? new AddressInfo(data.AddressInfo) : null;
        this.Error = data.Error ? new Error(data.Error) : null;
    }

    toString() {
        return `AddressInfoResponse: AddressInfo = ${this.AddressInfo ? this.AddressInfo.toString() : 'null'}, Error = ${this.Error ? this.Error.toString() : 'null'}]`;
    }
}

export default AddressInfoResponse;