Name Validation 2 C# Code Snippet


namespace name_validation_2_dot_net.REST
{
    /// <summary>
    /// Provides functionality to call the ServiceObjects DOTS Name Validation 2 REST API's NameInfoV2 endpoint,
    /// retrieving name validation information (e.g., name parsing, gender, scores) with fallback to a backup endpoint
    /// for reliability in live mode.
    /// </summary>
    public class NameInfoV2Client
    {
        private const string LiveBaseUrl = "https://sws.serviceobjects.com/NV2/api.svc/";
        private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/NV2/api.svc/";
        private const string TrialBaseUrl = "https://trial.serviceobjects.com/NV2/api.svc/";

        /// <summary>
        /// Synchronously calls the NameInfoV2 REST endpoint to retrieve name validation 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 name, option, license key.</param>
        /// <returns>Deserialized <see cref="NameInfoV2Response"/>.</returns>
        public static NameInfoV2Response Invoke(GetNameInfoInput input)
        {
            // Use query string parameters so missing/optional fields don't break
            // the URL as path parameters would.
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            NameInfoV2Response response = Helper.HttpGet<NameInfoV2Response>(url, input.TimeoutSeconds);

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

            return response;
        }

        /// <summary>
        /// Asynchronously calls the NameInfoV2 REST endpoint to retrieve name validation 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 name, option, license key.</param>
        /// <returns>Deserialized <see cref="NameInfoV2Response"/>.</returns>
        public static async Task<NameInfoV2Response> InvokeAsync(GetNameInfoInput input)
        {
            // Use query string parameters so missing/optional fields don't break
            // the URL as path parameters would.
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            NameInfoV2Response response = await Helper.HttpGetAsync<NameInfoV2Response>(url, input.TimeoutSeconds).ConfigureAwait(false);
            if (input.IsLive && !IsValid(response))
            {
                string fallbackUrl = BuildUrl(input, BackupBaseUrl);
                NameInfoV2Response fallbackResponse = await Helper.HttpGetAsync<NameInfoV2Response>(fallbackUrl, input.TimeoutSeconds).ConfigureAwait(false);
                return fallbackResponse;
            }

            return response;
        }

        // Build the full request URL, including URL-encoded query string
        public static string BuildUrl(GetNameInfoInput input, string baseUrl)
        {
            string qs = "NameInfoV2?" +
                        $"Name={Helper.UrlEncode(input.Name)}" +
                        $"&Option={Helper.UrlEncode(input.Option)}" +
                        $"&LicenseKey={Helper.UrlEncode(input.LicenseKey)}" +
                        "&format=json";
            return baseUrl + qs;
        }

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

        /// <summary>
        /// This is the primary operation for validating and parsing a name. Given a name and optional parameters,
        /// </summary>
        /// <param name="Name">The name to validate (required).</param>
        /// <param name="Option">Comma-separated list of options for additional processing (optional).</param>
        /// <param name="LicenseKey">Your license key to use the service.</param>
        /// <param name="IsLive">Option to use live service or trial service.</param>
        /// <param name="TimeoutSeconds">Timeout, in seconds, for the call to the service.</param>
        public record GetNameInfoInput(
            string Name = "",
            string Option = "",
            string LicenseKey = "",
            bool IsLive = true,
            int TimeoutSeconds = 15
        );
    }
}



namespace name_validation_2_dot_net.REST
{
    public class NameInfoV2Response
    {
        public NameInfoV2 NameInfoV2 { get; set; }

        public Error Error { get; set; }
        public override string ToString()
        {
            return $"NameInfoV2: {NameInfoV2}\n" +
                $"Error: {{{Error}}}";
        }
    }
    public class NameInfoV2
    {
        public BestGuessName BestGuessName { get; set; }
        public string NameIn { get; set; }
        public string NameClassification { get; set; }
        public string Prefix { get; set; }
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public string Suffix { get; set; }
        public bool FirstNameFound { get; set; }
        public bool IsCommonFirstName { get; set; }
        public string FirstNameOrigin { get; set; }
        public string FirstNameSimilar { get; set; }
        public bool LastNameFound { get; set; }
        public bool IsCommonLastName { get; set; }
        public string LastNameOrigin { get; set; }
        public string LastNameSimilar { get; set; }
        public string Gender { get; set; }
        public string FirstNameAlt { get; set; }
        public string MiddleNameAlt { get; set; }
        public string LastNameAlt { get; set; }
        public bool FirstNameAltFound { get; set; }
        public bool LastNameAltFound { get; set; }
        public string GenderAlt { get; set; }
        public string RelatedNames { get; set; }
        public bool IsCorrectedName { get; set; }
        public bool IsBusinessName { get; set; }
        public string BusinessName { get; set; }
        public int VulgarityScore { get; set; }
        public int CelebrityScore { get; set; }
        public int BogusScore { get; set; }
        public int GarbageScore { get; set; }
        public int FirstNameDictionaryScore { get; set; }
        public int MiddleNameDictionaryScore { get; set; }
        public int LastNameDictionaryScore { get; set; }
        public int OverallNameScore { get; set; }
        public string IsNameGood { get; set; }
        public string StatusCodes { get; set; }
        public string Status { get; set; }
        public override string ToString()
        {
            string Output = $"{{BestGuessName: {BestGuessName}\n" +
                $"NameIn: {NameIn}\n" +
                $"NameClassification: {NameClassification}\n" +
                $"Prefix: {Prefix}\n" +
                $"FirstName:  {FirstName}\n" +
                $"MiddleName: {MiddleName}\n" +
                $"LastName:  {LastName}\n" +
                $"Suffix:   {Suffix}\n" +
                $"FirstNameFound: {FirstNameFound}\n" +
                $"IsCommonFirstName: {IsCommonFirstName}\n" +
                $"FirstNameOrigin: {FirstNameOrigin}\n" +
                $"FirstNameSimilar: {FirstNameSimilar}\n" +
                $"LastNameFound: {LastNameFound}\n" +
                $"IsCommonLastName: {IsCommonLastName}\n" +
                $"LastNameOrigin: {LastNameOrigin}\n" +
                $"LastNameSimilar: {LastNameSimilar}\n" +
                $"Gender: {Gender}\n" +
                $"FirstNameAlt: {FirstNameAlt}\n" +
                $"MiddleNameAlt: {MiddleNameAlt}\n" +
                $"LastNameAlt: {LastNameAlt}\n" +
                $"FirstNameAltFound: {FirstNameAltFound}\n" +
                $"LastNameAltFound: {LastNameAltFound}\n" +
                $"GenderAlt: {GenderAlt}\n" +
                $"RelatedNames: {RelatedNames}\n" +
                $"IsCorrectedName: {IsCorrectedName}\n" +
                $"IsBusinessName: {IsBusinessName}\n" +
                $"BusinessName: {BusinessName}\n" +
                $"VulgarityScore: {VulgarityScore}\n" +
                $"CelebrityScore: {CelebrityScore}\n" +
                $"BogusScore: {BogusScore}\n" +
                $"GarbageScore: {GarbageScore}\n" +
                $"FirstNameDictionaryScore: {FirstNameDictionaryScore}\n" +
                $"MiddleNameDictionaryScore: {MiddleNameDictionaryScore}\n" +
                $"LastNameDictionaryScore: {LastNameDictionaryScore}\n" +
                $"OverallNameScore: {OverallNameScore}\n" +
                $"IsNameGood: {IsNameGood}\n" +
                $"StatusCodes: {StatusCodes}\n" +
                $"Status: {Status}\n";
            return Output;
        }

    }
    public class BestGuessName
    {
        public string Prefix { get; set; }
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public string Suffix { get; set; }
        public override string ToString()
        {
            return $"{{Prefix: {Prefix}\n" +
            $"FirstName: {FirstName}\n" +
            $"MiddleName: {MiddleName}\n" +
            $"LastName: {LastName}\n" +
            $"Suffix: {Suffix} }}\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}\n" +
                $"TypeCode: {TypeCode}\n" +
                $"Desc: {Desc}\n" +
                $"DescCode: {DescCode} ";
        }
    }

}


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

namespace name_validation_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);
    }
}

Name Validation 2 Python Code Snippet

import requests
from nv2_response import NameInfoV2Response, NameInfoV2, BestGuessName, Error

# Endpoint URLs for Name Validation 2 NameInfoV2 REST API
primary_url = 'https://sws.serviceobjects.com/NV2/api.svc/NameInfoV2?'
backup_url = 'https://swsbackup.serviceobjects.com/NV2/api.svc/NameInfoV2?'
trial_url = 'https://trial.serviceobjects.com/NV2/api.svc/NameInfoV2?'

def get_name_info_v2(
    name: str,
    option: str,
    license_key: str,
    is_live: bool = True,
    timeout_seconds: int = 15
) -> NameInfoV2Response:
    """
    Call Name Validation 2 NameInfoV2 API to retrieve name validation information.

    Parameters:
        name: The name to validate.
        option: Comma-separated list of options for additional processing (optional).
        license_key: Your license key to use the service.
        is_live: Value to determine whether to use the live or trial servers (default: True).
        timeout_seconds: Timeout, in seconds, for the call to the service (default: 15).

    Returns:
        NameInfoV2Response: Parsed JSON response with name information or error details.
    """
    params = {
        'Name': name,
        'Option': option,
        'LicenseKey': license_key,
        'format': 'json' 
    }

    # Select the base URL: production vs trial
    url = primary_url if is_live else trial_url

    # Attempt primary (or trial) endpoint first
    try:
        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 = getattr(response, 'Error', None)
        if not (error is None or getattr(error, 'TypeCode', None) != "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"NV2 service error: {data['Error']}")

            else:
                # Trial mode error is terminal
                raise RuntimeError(f"NV2 trial error: {data['Error']}")

        # Convert JSON response to NameInfoV2Response for structured access
        error = Error(**data.get('Error', {})) if data.get('Error') else None
        name_info_v2 = None
        if data.get('NameInfoV2'):
            best_guess_name = BestGuessName(**data['NameInfoV2'].get('BestGuessName', {})) if data['NameInfoV2'].get('BestGuessName') else None
            name_info_v2 = NameInfoV2(
                BestGuessName=best_guess_name,
                NameIn=data['NameInfoV2'].get('NameIn'),
                NameClassification=data['NameInfoV2'].get('NameClassification'),
                Prefix=data['NameInfoV2'].get('Prefix'),
                FirstName=data['NameInfoV2'].get('FirstName'),
                MiddleName=data['NameInfoV2'].get('MiddleName'),
                LastName=data['NameInfoV2'].get('LastName'),
                Suffix=data['NameInfoV2'].get('Suffix'),
                FirstNameFound=data['NameInfoV2'].get('FirstNameFound'),
                IsCommonFirstName=data['NameInfoV2'].get('IsCommonFirstName'),
                FirstNameOrigin=data['NameInfoV2'].get('FirstNameOrigin'),
                FirstNameSimilar=data['NameInfoV2'].get('FirstNameSimilar'),
                LastNameFound=data['NameInfoV2'].get('LastNameFound'),
                IsCommonLastName=data['NameInfoV2'].get('IsCommonLastName'),
                LastNameOrigin=data['NameInfoV2'].get('LastNameOrigin'),
                LastNameSimilar=data['NameInfoV2'].get('LastNameSimilar'),
                Gender=data['NameInfoV2'].get('Gender'),
                FirstNameAlt=data['NameInfoV2'].get('FirstNameAlt'),
                MiddleNameAlt=data['NameInfoV2'].get('MiddleNameAlt'),
                LastNameAlt=data['NameInfoV2'].get('LastNameAlt'),
                FirstNameAltFound=data['NameInfoV2'].get('FirstNameAltFound'),
                LastNameAltFound=data['NameInfoV2'].get('LastNameAltFound'),
                GenderAlt=data['NameInfoV2'].get('GenderAlt'),
                RelatedNames=data['NameInfoV2'].get('RelatedNames'),
                IsCorrectedName=data['NameInfoV2'].get('IsCorrectedName'),
                IsBusinessName=data['NameInfoV2'].get('IsBusinessName'),
                BusinessName=data['NameInfoV2'].get('BusinessName'),
                VulgarityScore=data['NameInfoV2'].get('VulgarityScore'),
                CelebrityScore=data['NameInfoV2'].get('CelebrityScore'),
                BogusScore=data['NameInfoV2'].get('BogusScore'),
                GarbageScore=data['NameInfoV2'].get('GarbageScore'),
                FirstNameDictionaryScore=data['NameInfoV2'].get('FirstNameDictionaryScore'),
                MiddleNameDictionaryScore=data['NameInfoV2'].get('MiddleNameDictionaryScore'),
                LastNameDictionaryScore=data['NameInfoV2'].get('LastNameDictionaryScore'),
                OverallNameScore=data['NameInfoV2'].get('OverallNameScore'),
                IsNameGood=data['NameInfoV2'].get('IsNameGood'),
                StatusCodes=data['NameInfoV2'].get('StatusCodes'),
                Status=data['NameInfoV2'].get('Status')
            )

        return NameInfoV2Response(
            NameInfoV2=name_info_v2,
            Error=error
        )

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

                # Convert JSON response to NameInfoV2Response for structured access
                error = Error(**data.get('Error', {})) if data.get('Error') else None
                name_info_v2 = None
                if data.get('NameInfoV2'):
                    best_guess_name = BestGuessName(**data['NameInfoV2'].get('BestGuessName', {})) if data['NameInfoV2'].get('BestGuessName') else None
                    name_info_v2 = NameInfoV2(
                        BestGuessName=best_guess_name,
                        NameIn=data['NameInfoV2'].get('NameIn'),
                        NameClassification=data['NameInfoV2'].get('NameClassification'),
                        Prefix=data['NameInfoV2'].get('Prefix'),
                        FirstName=data['NameInfoV2'].get('FirstName'),
                        MiddleName=data['NameInfoV2'].get('MiddleName'),
                        LastName=data['NameInfoV2'].get('LastName'),
                        Suffix=data['NameInfoV2'].get('Suffix'),
                        FirstNameFound=data['NameInfoV2'].get('FirstNameFound'),
                        IsCommonFirstName=data['NameInfoV2'].get('IsCommonFirstName'),
                        FirstNameOrigin=data['NameInfoV2'].get('FirstNameOrigin'),
                        FirstNameSimilar=data['NameInfoV2'].get('FirstNameSimilar'),
                        LastNameFound=data['NameInfoV2'].get('LastNameFound'),
                        IsCommonLastName=data['NameInfoV2'].get('IsCommonLastName'),
                        LastNameOrigin=data['NameInfoV2'].get('LastNameOrigin'),
                        LastNameSimilar=data['NameInfoV2'].get('LastNameSimilar'),
                        Gender=data['NameInfoV2'].get('Gender'),
                        FirstNameAlt=data['NameInfoV2'].get('FirstNameAlt'),
                        MiddleNameAlt=data['NameInfoV2'].get('MiddleNameAlt'),
                        LastNameAlt=data['NameInfoV2'].get('LastNameAlt'),
                        FirstNameAltFound=data['NameInfoV2'].get('FirstNameAltFound'),
                        LastNameAltFound=data['NameInfoV2'].get('LastNameAltFound'),
                        GenderAlt=data['NameInfoV2'].get('GenderAlt'),
                        RelatedNames=data['NameInfoV2'].get('RelatedNames'),
                        IsCorrectedName=data['NameInfoV2'].get('IsCorrectedName'),
                        IsBusinessName=data['NameInfoV2'].get('IsBusinessName'),
                        BusinessName=data['NameInfoV2'].get('BusinessName'),
                        VulgarityScore=data['NameInfoV2'].get('VulgarityScore'),
                        CelebrityScore=data['NameInfoV2'].get('CelebrityScore'),
                        BogusScore=data['NameInfoV2'].get('BogusScore'),
                        GarbageScore=data['NameInfoV2'].get('GarbageScore'),
                        FirstNameDictionaryScore=data['NameInfoV2'].get('FirstNameDictionaryScore'),
                        MiddleNameDictionaryScore=data['NameInfoV2'].get('MiddleNameDictionaryScore'),
                        LastNameDictionaryScore=data['NameInfoV2'].get('LastNameDictionaryScore'),
                        OverallNameScore=data['NameInfoV2'].get('OverallNameScore'),
                        IsNameGood=data['NameInfoV2'].get('IsNameGood'),
                        StatusCodes=data['NameInfoV2'].get('StatusCodes'),
                        Status=data['NameInfoV2'].get('Status')
                    )

                return NameInfoV2Response(
                    NameInfoV2=name_info_v2,
                    Error=error
                )
            except Exception as backup_exc:
                raise RuntimeError("NV2 service unreachable on both endpoints") from backup_exc
        else:
            raise RuntimeError(f"NV2 trial error: {str(req_exc)}") from req_exc


from dataclasses import dataclass
from typing import Optional

@dataclass
class BestGuessName:
    Prefix: Optional[str] = None
    FirstName: Optional[str] = None
    MiddleName: Optional[str] = None
    LastName: Optional[str] = None
    Suffix: Optional[str] = None

    def __str__(self) -> str:
        return (f"Prefix: {self.Prefix}\n"
                f"FirstName: {self.FirstName}\n"
                f"MiddleName: {self.MiddleName}\n"
                f"LastName: {self.LastName}\n"
                f"Suffix: {self.Suffix}")

@dataclass
class NameInfoV2:
    BestGuessName: Optional[BestGuessName] = None
    NameIn: Optional[str] = None
    NameClassification: Optional[str] = None
    Prefix: Optional[str] = None
    FirstName: Optional[str] = None
    MiddleName: Optional[str] = None
    LastName: Optional[str] = None
    Suffix: Optional[str] = None
    FirstNameFound: Optional[bool] = None
    IsCommonFirstName: Optional[bool] = None
    FirstNameOrigin: Optional[str] = None
    FirstNameSimilar: Optional[str] = None
    LastNameFound: Optional[bool] = None
    IsCommonLastName: Optional[bool] = None
    LastNameOrigin: Optional[str] = None
    LastNameSimilar: Optional[str] = None
    Gender: Optional[str] = None
    FirstNameAlt: Optional[str] = None
    MiddleNameAlt: Optional[str] = None
    LastNameAlt: Optional[str] = None
    FirstNameAltFound: Optional[bool] = None
    LastNameAltFound: Optional[bool] = None
    GenderAlt: Optional[str] = None
    RelatedNames: Optional[str] = None
    IsCorrectedName: Optional[bool] = None
    IsBusinessName: Optional[bool] = None
    BusinessName: Optional[str] = None
    VulgarityScore: Optional[int] = None
    CelebrityScore: Optional[int] = None
    BogusScore: Optional[int] = None
    GarbageScore: Optional[int] = None
    FirstNameDictionaryScore: Optional[int] = None
    MiddleNameDictionaryScore: Optional[int] = None
    LastNameDictionaryScore: Optional[int] = None
    OverallNameScore: Optional[int] = None
    IsNameGood: Optional[str] = None
    StatusCodes: Optional[str] = None
    Status: Optional[str] = None

    def __str__(self) -> str:
        return (f"{{BestGuessName: {self.BestGuessName.__str__() if self.BestGuessName else 'None'}\n"
                f"NameIn: {self.NameIn}\n"
                f"NameClassification: {self.NameClassification}\n"
                f"Prefix: {self.Prefix}\n"
                f"FirstName: {self.FirstName}\n"
                f"MiddleName: {self.MiddleName}\n"
                f"LastName: {self.LastName}\n"
                f"Suffix: {self.Suffix}\n"
                f"FirstNameFound: {self.FirstNameFound}\n"
                f"IsCommonFirstName: {self.IsCommonFirstName}\n"
                f"FirstNameOrigin: {self.FirstNameOrigin}\n"
                f"FirstNameSimilar: {self.FirstNameSimilar}\n"
                f"LastNameFound: {self.LastNameFound}\n"
                f"IsCommonLastName: {self.IsCommonLastName}\n"
                f"LastNameOrigin: {self.LastNameOrigin}\n"
                f"LastNameSimilar: {self.LastNameSimilar}\n"
                f"Gender: {self.Gender}\n"
                f"FirstNameAlt: {self.FirstNameAlt}\n"
                f"MiddleNameAlt: {self.MiddleNameAlt}\n"
                f"LastNameAlt: {self.LastNameAlt}\n"
                f"FirstNameAltFound: {self.FirstNameAltFound}\n"
                f"LastNameAltFound: {self.LastNameAltFound}\n"
                f"GenderAlt: {self.GenderAlt}\n"
                f"RelatedNames: {self.RelatedNames}\n"
                f"IsCorrectedName: {self.IsCorrectedName}\n"
                f"IsBusinessName: {self.IsBusinessName}\n"
                f"BusinessName: {self.BusinessName}\n"
                f"VulgarityScore: {self.VulgarityScore}\n"
                f"CelebrityScore: {self.CelebrityScore}\n"
                f"BogusScore: {self.BogusScore}\n"
                f"GarbageScore: {self.GarbageScore}\n"
                f"FirstNameDictionaryScore: {self.FirstNameDictionaryScore}\n"
                f"MiddleNameDictionaryScore: {self.MiddleNameDictionaryScore}\n"
                f"LastNameDictionaryScore: {self.LastNameDictionaryScore}\n"
                f"OverallNameScore: {self.OverallNameScore}\n"
                f"IsNameGood: {self.IsNameGood}\n"
                f"StatusCodes: {self.StatusCodes}\n"
                f"Status: {self.Status}\n")

@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"Type: {self.Type}\n"
                f"TypeCode: {self.TypeCode}\n"
                f"Desc: {self.Desc}\n"
                f"DescCode: {self.DescCode} ")

@dataclass
class NameInfoV2Response:
    NameInfoV2: Optional[NameInfoV2] = None
    Error: Optional[Error] = None

    def __str__(self) -> str:
        name_info = str(self.NameInfoV2) if self.NameInfoV2 else "None"
        error = str(self.Error) if self.Error else "None"
        return (f"NameInfoV2: {name_info}\n"
                f"Error: {error}")

Name Validation 2 NodeJS Code Snippet

import axios from 'axios';
import querystring from 'querystring';
import { NameInfoV2Response } from './nv2_response.js';

/**
 * @constant
 * @type {string}
 * @description The base URL for the live ServiceObjects Name Validation 2 API service.
 */
const LiveBaseUrl = 'https://sws.serviceobjects.com/NV2/api.svc/';

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

/**
 * @constant
 * @type {string}
 * @description The base URL for the trial ServiceObjects Name Validation 2 API service.
 */
const TrialBaseUrl = 'https://trial.serviceobjects.com/NV2/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'.
 * </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 NameInfoV2 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}NameInfoV2?${querystring.stringify(params)}&format=json`;

/**
 * <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<NameInfoV2Response>">A promise that resolves to a NameInfoV2Response 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 NameInfoV2Response(response.data);
    } catch (error) {
        throw new Error(`HTTP request failed: ${error.message}`);
    }
};

/**
 * <summary>
 * Provides functionality to call the ServiceObjects Name Validation 2 API's NameInfoV2 endpoint,
 * retrieving name validation information with fallback to a backup endpoint for reliability in live mode.
 * </summary>
 */
const NameInfoV2Client = {
    /**
     * <summary>
     * Asynchronously invokes the NameInfoV2 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} Name - The name to validate.
     * @param {string} Option - Comma-separated list of options for additional processing (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<NameInfoV2Response>} - A promise that resolves to a NameInfoV2Response object.
     */
    async invokeAsync(Name, Option = '', LicenseKey, isLive = true, timeoutSeconds = 15) {
        const params = {
            Name,
            Option,
            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 isValid(fallbackResponse) ? fallbackResponse : response;
        }

        return response;
    },

    /**
     * <summary>
     * Synchronously invokes the NameInfoV2 API endpoint by wrapping the async call
     * and awaiting its result immediately.
     * </summary>
     * @returns {NameInfoV2Response} - A NameInfoV2Response object with name validation details or an error.
     */
    invoke(Name, Option = '', LicenseKey, isLive = true, timeoutSeconds = 15) {
        return (async () => await this.invokeAsync(
            Name, Option, LicenseKey, isLive, timeoutSeconds
        ))();
    }
};

export { NameInfoV2Client, NameInfoV2Response };


class BestGuessName {
    constructor(data = {}) {
        this.Prefix = data.Prefix;
        this.FirstName = data.FirstName;
        this.MiddleName = data.MiddleName;
        this.LastName = data.LastName;
        this.Suffix = data.Suffix;
    }

    toString() {
        return `{Prefix: ${this.Prefix}\n` +
               `FirstName: ${this.FirstName}\n` +
               `MiddleName: ${this.MiddleName}\n` +
               `LastName: ${this.LastName}\n` +
               `Suffix: ${this.Suffix}}`;
    }
}

class NameInfoV2 {
    constructor(data = {}) {
        this.BestGuessName = data.BestGuessName ? new BestGuessName(data.BestGuessName) : "";
        this.NameIn = data.NameIn;
        this.NameClassification = data.NameClassification;
        this.Prefix = data.Prefix;
        this.FirstName = data.FirstName;
        this.MiddleName = data.MiddleName;
        this.LastName = data.LastName;
        this.Suffix = data.Suffix;
        this.FirstNameFound = data.FirstNameFound;
        this.IsCommonFirstName = data.IsCommonFirstName;
        this.FirstNameOrigin = data.FirstNameOrigin;
        this.FirstNameSimilar = data.FirstNameSimilar;
        this.LastNameFound = data.LastNameFound;
        this.IsCommonLastName = data.IsCommonLastName;
        this.LastNameOrigin = data.LastNameOrigin;
        this.LastNameSimilar = data.LastNameSimilar;
        this.Gender = data.Gender;
        this.FirstNameAlt = data.FirstNameAlt;
        this.MiddleNameAlt = data.MiddleNameAlt;
        this.LastNameAlt = data.LastNameAlt;
        this.FirstNameAltFound = data.FirstNameAltFound;
        this.LastNameAltFound = data.LastNameAltFound;
        this.GenderAlt = data.GenderAlt;
        this.RelatedNames = data.RelatedNames;
        this.IsCorrectedName = data.IsCorrectedName;
        this.IsBusinessName = data.IsBusinessName;
        this.BusinessName = data.BusinessName;
        this.VulgarityScore = data.VulgarityScore;
        this.CelebrityScore = data.CelebrityScore;
        this.BogusScore = data.BogusScore;
        this.GarbageScore = data.GarbageScore;
        this.FirstNameDictionaryScore = data.FirstNameDictionaryScore;
        this.MiddleNameDictionaryScore = data.MiddleNameDictionaryScore;
        this.LastNameDictionaryScore = data.LastNameDictionaryScore;
        this.OverallNameScore = data.OverallNameScore;
        this.IsNameGood = data.IsNameGood;
        this.StatusCodes = data.StatusCodes;
        this.Status = data.Status;
    }

    toString() {
        return `{BestGuessName: ${this.BestGuessName ? this.BestGuessName.toString() : 'null'}\n` +
               `NameIn: ${this.NameIn}\n` +
               `NameClassification: ${this.NameClassification}\n` +
               `Prefix: ${this.Prefix}\n` +
               `FirstName: ${this.FirstName}\n` +
               `MiddleName: ${this.MiddleName}\n` +
               `LastName: ${this.LastName}\n` +
               `Suffix: ${this.Suffix}\n` +
               `FirstNameFound: ${this.FirstNameFound}\n` +
               `IsCommonFirstName: ${this.IsCommonFirstName}\n` +
               `FirstNameOrigin: ${this.FirstNameOrigin}\n` +
               `FirstNameSimilar: ${this.FirstNameSimilar}\n` +
               `LastNameFound: ${this.LastNameFound}\n` +
               `IsCommonLastName: ${this.IsCommonLastName}\n` +
               `LastNameOrigin: ${this.LastNameOrigin}\n` +
               `LastNameSimilar: ${this.LastNameSimilar}\n` +
               `Gender: ${this.Gender}\n` +
               `FirstNameAlt: ${this.FirstNameAlt}\n` +
               `MiddleNameAlt: ${this.MiddleNameAlt}\n` +
               `LastNameAlt: ${this.LastNameAlt}\n` +
               `FirstNameAltFound: ${this.FirstNameAltFound}\n` +
               `LastNameAltFound: ${this.LastNameAltFound}\n` +
               `GenderAlt: ${this.GenderAlt}\n` +
               `RelatedNames: ${this.RelatedNames}\n` +
               `IsCorrectedName: ${this.IsCorrectedName}\n` +
               `IsBusinessName: ${this.IsBusinessName}\n` +
               `BusinessName: ${this.BusinessName}\n` +
               `VulgarityScore: ${this.VulgarityScore}\n` +
               `CelebrityScore: ${this.CelebrityScore}\n` +
               `BogusScore: ${this.BogusScore}\n` +
               `GarbageScore: ${this.GarbageScore}\n` +
               `FirstNameDictionaryScore: ${this.FirstNameDictionaryScore}\n` +
               `MiddleNameDictionaryScore: ${this.MiddleNameDictionaryScore}\n` +
               `LastNameDictionaryScore: ${this.LastNameDictionaryScore}\n` +
               `OverallNameScore: ${this.OverallNameScore}\n` +
               `IsNameGood: ${this.IsNameGood}\n` +
               `StatusCodes: ${this.StatusCodes}\n` +
               `Status: ${this.Status}\n`;
    }
}

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

    toString() {
        return `Type: ${this.Type}\n` +
               `TypeCode: ${this.TypeCode}\n` +
               `Desc: ${this.Desc}\n` +
               `DescCode: ${this.DescCode} `;
    }
}

class NameInfoV2Response {
    constructor(data = {}) {
        this.NameInfoV2 = data.NameInfoV2 ? new NameInfoV2(data.NameInfoV2) : null;
        this.Error = data.Error ? new Error(data.Error) : null;
    }

    toString() {
        return `NameInfoV2: ${(this.NameInfoV2 ? this.NameInfoV2.toString() : 'null')}\n` +
               `Error: ${this.Error ? this.Error.toString() : 'null'}`;
    }
}

export{ NameInfoV2Response };