Complete Integration Examples

Basic API Client Setup

Set up a robust API client with proper authentication, error handling, and rate limiting:
class CountryStateCityAPI {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseURL = 'https://api.countrystatecity.in/v1';
  }

  async request(endpoint) {
    try {
      const response = await fetch(`${this.baseURL}${endpoint}`, {
        headers: {
          'X-CSCAPI-KEY': this.apiKey,
          'Content-Type': 'application/json'
        }
      });

      if (!response.ok) {
        if (response.status === 401) {
          throw new Error('Invalid API key. Please check your credentials.');
        } else if (response.status === 429) {
          throw new Error('Rate limit exceeded. Please try again later.');
        } else {
          throw new Error(`API error: ${response.status}`);
        }
      }

      return await response.json();
    } catch (error) {
      console.error('API request failed:', error);
      throw error;
    }
  }

  async getCountries() {
    return await this.request('/countries');
  }

  async getStates(countryCode) {
    return await this.request(`/countries/${countryCode}/states`);
  }

  async getCities(countryCode, stateCode = null) {
    const endpoint = stateCode 
      ? `/countries/${countryCode}/states/${stateCode}/cities`
      : `/countries/${countryCode}/cities`;
    return await this.request(endpoint);
  }

  async getCountryDetails(countryCode) {
    return await this.request(`/countries/${countryCode}`);
  }
}

// Usage
const api = new CountryStateCityAPI('YOUR_API_KEY');
const countries = await api.getCountries();
const usStates = await api.getStates('US');
const californiaCities = await api.getCities('US', 'CA');

Real-World Use Cases

1. Complete Registration Form with Cascading Dropdowns

Build a comprehensive user registration form with dependent location selectors:
import React, { useState, useEffect } from 'react';

const LocationSelector = ({ apiKey, onLocationChange }) => {
  const [countries, setCountries] = useState([]);
  const [states, setStates] = useState([]);
  const [cities, setCities] = useState([]);
  const [selectedCountry, setSelectedCountry] = useState('');
  const [selectedState, setSelectedState] = useState('');
  const [selectedCity, setSelectedCity] = useState('');
  const [loading, setLoading] = useState(false);

  const api = new CountryStateCityAPI(apiKey);

  // Load countries on component mount
  useEffect(() => {
    const loadCountries = async () => {
      try {
        setLoading(true);
        const countriesData = await api.getCountries();
        setCountries(countriesData);
      } catch (error) {
        console.error('Failed to load countries:', error);
      } finally {
        setLoading(false);
      }
    };
    loadCountries();
  }, []);

  // Load states when country changes
  useEffect(() => {
    if (selectedCountry) {
      const loadStates = async () => {
        try {
          setLoading(true);
          const statesData = await api.getStates(selectedCountry);
          setStates(statesData);
          setSelectedState(''); // Reset state selection
          setCities([]); // Clear cities
          setSelectedCity(''); // Reset city selection
        } catch (error) {
          console.error('Failed to load states:', error);
        } finally {
          setLoading(false);
        }
      };
      loadStates();
    }
  }, [selectedCountry]);

  // Load cities when state changes
  useEffect(() => {
    if (selectedCountry && selectedState) {
      const loadCities = async () => {
        try {
          setLoading(true);
          const citiesData = await api.getCities(selectedCountry, selectedState);
          setCities(citiesData);
          setSelectedCity(''); // Reset city selection
        } catch (error) {
          console.error('Failed to load cities:', error);
        } finally {
          setLoading(false);
        }
      };
      loadCities();
    }
  }, [selectedState]);

  return (
    <div className="location-selector">
      <div className="form-group">
        <label htmlFor="country">Country *</label>
        <select
          id="country"
          value={selectedCountry}
          onChange={(e) => setSelectedCountry(e.target.value)}
          disabled={loading}
          required
        >
          <option value="">Select Country</option>
          {countries.map(country => (
            <option key={country.iso2} value={country.iso2}>
              {country.emoji} {country.name}
            </option>
          ))}
        </select>
      </div>

      <div className="form-group">
        <label htmlFor="state">State/Province *</label>
        <select
          id="state"
          value={selectedState}
          onChange={(e) => setSelectedState(e.target.value)}
          disabled={loading || !selectedCountry}
          required
        >
          <option value="">Select State</option>
          {states.map(state => (
            <option key={state.iso2} value={state.iso2}>
              {state.name}
            </option>
          ))}
        </select>
      </div>

      <div className="form-group">
        <label htmlFor="city">City *</label>
        <select
          id="city"
          value={selectedCity}
          onChange={(e) => setSelectedCity(e.target.value)}
          disabled={loading || !selectedState}
          required
        >
          <option value="">Select City</option>
          {cities.map(city => (
            <option key={city.id} value={city.id}>
              {city.name}
            </option>
          ))}
        </select>
      </div>

      {loading && <div className="loading">Loading...</div>}
    </div>
  );
};

2. E-commerce Shipping Calculator

Calculate shipping costs and delivery times based on geographical locations:
class ShippingCalculator {
  constructor(apiKey) {
    this.api = new CountryStateCityAPI(apiKey);
    this.shippingRates = {
      domestic: { base: 5.99, perKg: 1.50, deliveryDays: '2-3' },
      international: { 
        asia: { base: 25.99, perKg: 8.50, deliveryDays: '7-10' },
        europe: { base: 29.99, perKg: 9.50, deliveryDays: '7-12' },
        americas: { base: 19.99, perKg: 7.50, deliveryDays: '5-8' },
        africa: { base: 35.99, perKg: 12.50, deliveryDays: '10-15' }
      }
    };
  }

  async calculateShipping(fromCountryCode, toCountryCode, weight) {
    try {
      const [fromCountry, toCountry] = await Promise.all([
        this.api.getCountryDetails(fromCountryCode),
        this.api.getCountryDetails(toCountryCode)
      ]);

      // Domestic shipping
      if (fromCountryCode === toCountryCode) {
        const rate = this.shippingRates.domestic;
        return {
          cost: rate.base + (weight * rate.perKg),
          deliveryTime: rate.deliveryDays,
          type: 'Domestic',
          from: fromCountry.name,
          to: toCountry.name
        };
      }

      // International shipping
      const toRegion = this.getRegion(toCountry.region);
      const rate = this.shippingRates.international[toRegion];
      
      return {
        cost: rate.base + (weight * rate.perKg),
        deliveryTime: rate.deliveryDays,
        type: 'International',
        region: toRegion,
        from: fromCountry.name,
        to: toCountry.name
      };

    } catch (error) {
      throw new Error(`Shipping calculation failed: ${error.message}`);
    }
  }

  getRegion(countryRegion) {
    const regionMap = {
      'Asia': 'asia',
      'Europe': 'europe',
      'Americas': 'americas',
      'Africa': 'africa'
    };
    return regionMap[countryRegion] || 'international';
  }
}

// Usage
const calculator = new ShippingCalculator('YOUR_API_KEY');
const shippingInfo = await calculator.calculateShipping('US', 'CA', 2.5);
console.log(`Shipping cost: $${shippingInfo.cost.toFixed(2)}`);
console.log(`Delivery: ${shippingInfo.deliveryTime} business days`);

3. Multi-Currency Price Display

Display prices in local currencies based on user location:
class PriceLocalization {
  constructor(apiKey) {
    this.api = new CountryStateCityAPI(apiKey);
    this.exchangeRates = {}; // Cache exchange rates
    this.baseCurrency = 'USD';
  }

  async getLocalizedPrice(basePrice, userCountryCode) {
    try {
      const country = await this.api.getCountryDetails(userCountryCode);
      const currency = country.currency;

      if (currency === this.baseCurrency) {
        return {
          amount: basePrice,
          currency: currency,
          symbol: country.currency_symbol || '$',
          formatted: `${country.currency_symbol || '$'}${basePrice.toFixed(2)}`
        };
      }

      // Get exchange rate (you'd typically use a service like exchangerates-api.io)
      const rate = await this.getExchangeRate(this.baseCurrency, currency);
      const localAmount = basePrice * rate;

      return {
        amount: localAmount,
        currency: currency,
        symbol: country.currency_symbol || '',
        formatted: `${country.currency_symbol || ''}${localAmount.toFixed(2)}`,
        exchangeRate: rate,
        originalPrice: basePrice,
        originalCurrency: this.baseCurrency
      };

    } catch (error) {
      console.error('Price localization failed:', error);
      // Fallback to base price
      return {
        amount: basePrice,
        currency: this.baseCurrency,
        symbol: '$',
        formatted: `$${basePrice.toFixed(2)}`
      };
    }
  }

  async getExchangeRate(from, to) {
    // This is a placeholder - use a real exchange rate service
    const cacheKey = `${from}-${to}`;
    
    if (this.exchangeRates[cacheKey] && 
        this.exchangeRates[cacheKey].timestamp > Date.now() - 3600000) {
      return this.exchangeRates[cacheKey].rate;
    }

    // Mock exchange rate - replace with real service
    const mockRates = { 'EUR': 0.85, 'GBP': 0.73, 'CAD': 1.25, 'INR': 74.5 };
    const rate = mockRates[to] || 1;
    
    this.exchangeRates[cacheKey] = {
      rate: rate,
      timestamp: Date.now()
    };
    
    return rate;
  }
}

Best Practices and Optimization

Caching Strategy for Performance

Implement intelligent caching to minimize API calls and improve performance:
class OptimizedCountryStateCityAPI extends CountryStateCityAPI {
  constructor(apiKey, cacheOptions = {}) {
    super(apiKey);
    this.cache = new Map();
    this.cacheTTL = cacheOptions.ttl || 3600000; // 1 hour default
    this.requestQueue = new Map(); // Prevent duplicate requests
  }

  async request(endpoint) {
    // Check cache first
    const cached = this.cache.get(endpoint);
    if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
      return cached.data;
    }

    // Check if request is already in progress
    if (this.requestQueue.has(endpoint)) {
      return await this.requestQueue.get(endpoint);
    }

    // Make request and cache the promise
    const requestPromise = super.request(endpoint);
    this.requestQueue.set(endpoint, requestPromise);

    try {
      const data = await requestPromise;
      this.cache.set(endpoint, {
        data,
        timestamp: Date.now()
      });
      return data;
    } finally {
      this.requestQueue.delete(endpoint);
    }
  }

  // Preload commonly used data
  async preloadEssentials() {
    const essentials = [
      '/countries',
      '/countries/US/states',
      '/countries/GB/states',
      '/countries/CA/states'
    ];

    await Promise.all(essentials.map(endpoint => this.request(endpoint)));
  }
}

Rate Limiting and Error Handling

Implement robust error handling and rate limiting strategies:
class ResilientCountryStateCityAPI extends CountryStateCityAPI {
  constructor(apiKey, options = {}) {
    super(apiKey);
    this.maxRetries = options.maxRetries || 3;
    this.baseDelay = options.baseDelay || 1000;
    this.requestsPerSecond = options.requestsPerSecond || 2;
    this.requestQueue = [];
    this.processing = false;
    
    this.startRequestProcessor();
  }

  async request(endpoint) {
    return new Promise((resolve, reject) => {
      this.requestQueue.push({ endpoint, resolve, reject, retries: 0 });
      this.processQueue();
    });
  }

  async processQueue() {
    if (this.processing || this.requestQueue.length === 0) return;
    
    this.processing = true;
    
    while (this.requestQueue.length > 0) {
      const { endpoint, resolve, reject, retries } = this.requestQueue.shift();
      
      try {
        const data = await this.makeRequestWithRetry(endpoint, retries);
        resolve(data);
      } catch (error) {
        reject(error);
      }
      
      // Rate limiting: wait between requests
      await this.sleep(1000 / this.requestsPerSecond);
    }
    
    this.processing = false;
  }

  async makeRequestWithRetry(endpoint, retries) {
    try {
      return await super.request(endpoint);
    } catch (error) {
      if (retries >= this.maxRetries) {
        throw error;
      }

      if (error.message.includes('Rate limit exceeded') || 
          error.message.includes('500') || 
          error.message.includes('503')) {
        
        const delay = this.baseDelay * Math.pow(2, retries);
        await this.sleep(delay);
        return this.makeRequestWithRetry(endpoint, retries + 1);
      }
      
      throw error;
    }
  }

  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  startRequestProcessor() {
    setInterval(() => this.processQueue(), 100);
  }
}

Need More Help?

All code examples are production-ready and include proper error handling, caching, and rate limiting. Remember to replace YOUR_API_KEY with your actual API key from the Country State City portal.