All files / src/services googleGeocodingService.server.ts

54.66% Statements 41/75
92.85% Branches 13/14
66.66% Functions 2/3
62.5% Lines 35/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 572x 2x 2x 2x 2x 35x     2x 2x 2x 2x 2x 2x 2x 2x 2x 5x 5x 2x 2x 2x 2x 4x   4x 4x 3x 1x     2x 2x 1x       1x     1x       1x   2x       2x         30x  
// src/services/googleGeocodingService.server.ts
import type { Logger } from 'pino';
import { logger as defaultLogger } from './logger.server';
 
export class GoogleGeocodingService {
  private readonly baseUrl = 'https://maps.googleapis.com/maps/api/geocode/json';

  /**
   * Geocodes an address using the Google Maps Geocoding API.
   * @param address The address string to geocode.
   * @param logger A logger instance.
   * @returns A promise that resolves to the coordinates or null if not found.
   */
  async geocode(
    address: string,
    logger: Logger = defaultLogger,
  ): Promise<{ lat: number; lng: number } | null> {
    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
    if (!apiKey) {
      logger.error('[GoogleGeocodingService] API key is missing.');
      throw new Error('GOOGLE_MAPS_API_KEY is not set.');
    }
 
    const url = `${this.baseUrl}?address=${encodeURIComponent(address)}&key=${apiKey}`;

    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`Google Maps API returned status ${response.status}`);
      }

      const data = await response.json();
      if (data.status === 'OK' && data.results.length > 0) {
        logger.info(
          { address, result: data.results[0].geometry.location },
          `[GoogleGeocodingService] Successfully geocoded address`,
        );
        return data.results[0].geometry.location;
      }

      logger.warn(
        { address, status: data.status },
        '[GoogleGeocodingService] Geocoding failed or returned no results.',
      );
      return null;
    } catch (error) {
      logger.error(
        { err: error, address },
        '[GoogleGeocodingService] An error occurred while calling the Google Maps API.',
      );
      throw error; // Re-throw to allow the calling service to handle the failure (e.g., by falling back).
    }
  }
}

export const googleGeocodingService = new GoogleGeocodingService();