Skip to content
Last updated

Location Operations

Location endpoints provide comprehensive location search and geocoding services for car rental operations. These endpoints enable users to find pickup and drop-off locations with autocomplete functionality and detailed location information.

Search for car rental locations using text queries. This endpoint provides autocomplete functionality, returning location predictions that match the search query for an enhanced user experience.

Endpoint

GET /locations?query={query}

Authentication

This endpoint requires authentication. Include your JWT access token in the Authorization header:

Authorization: Bearer YOUR_ACCESS_TOKEN

Query Parameters

ParameterTypeRequiredDescription
querystringYesSearch query text (minimum 2 characters)

Example Request

curl -X GET "https://api.pro.yolcu360.com/api/v1/locations?query=istanbul" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

Success Response (200 OK):

[
  {
    "placeId": "ChIJOwg_06VPwokRYv534QaPC8g",
    "description": "Istanbul, Turkey",
    "mainText": "Istanbul",
    "secondaryText": "Turkey",
    "types": [
      "locality",
      "political"
    ]
  },
  {
    "placeId": "ChIJB3uraJq9yhQRvHRAVQ6KFT4",
    "description": "Istanbul Airport (IST), Tayakadın, Arnavutköy/İstanbul, Turkey",
    "mainText": "Istanbul Airport (IST)",
    "secondaryText": "Tayakadın, Arnavutköy/İstanbul, Turkey",
    "types": [
      "airport",
      "establishment",
      "point_of_interest"
    ]
  },
  {
    "placeId": "ChIJ8dYSQGq8yhQRy_TlKn0Qmgg",
    "description": "Sabiha Gökçen International Airport (SAW), Pendik/İstanbul, Turkey",
    "mainText": "Sabiha Gökçen International Airport (SAW)",
    "secondaryText": "Pendik/İstanbul, Turkey",
    "types": [
      "airport",
      "establishment",
      "point_of_interest"
    ]
  },
  {
    "placeId": "ChIJh8tEqiq9yhQR4Es7hO_KWw8",
    "description": "Istanbul Atatürk Airport (ISL), Yeşilköy, Bakırköy/İstanbul, Turkey",
    "mainText": "Istanbul Atatürk Airport (ISL)",
    "secondaryText": "Yeşilköy, Bakırköy/İstanbul, Turkey",
    "types": [
      "airport",
      "establishment",
      "point_of_interest"
    ]
  },
  {
    "placeId": "ChIJu46S-ZNjyhQROG9z8KiBUUs",
    "description": "Sultanahmet, Fatih/İstanbul, Turkey",
    "mainText": "Sultanahmet",
    "secondaryText": "Fatih/İstanbul, Turkey",
    "types": [
      "neighborhood",
      "political"
    ]
  }
]

Response Fields

FieldTypeDescription
placeIdstringUnique identifier for the location
descriptionstringFull description of the location
mainTextstringPrimary location text (typically the name)
secondaryTextstringSecondary descriptive text (typically the address)
typesarrayLocation types (e.g., airport, city, neighborhood)

Location Types

TypeDescription
airportAirport locations
localityCities or towns
neighborhoodDistricts or neighborhoods
establishmentBusiness establishments
point_of_interestNotable landmarks or points of interest
politicalAdministrative boundaries

Get Location Details

Retrieve detailed information about a specific location using its place ID. This endpoint provides comprehensive location data including coordinates, timezone, and administrative information.

Endpoint

GET /locations/{placeId}

Authentication

This endpoint requires authentication. Include your JWT access token in the Authorization header.

Path Parameters

ParameterTypeRequiredDescription
placeIdstringYesUnique place identifier from location search

Example Request

curl -X GET https://api.pro.yolcu360.com/api/v1/locations/ChIJOwg_06VPwokRYv534QaPC8g \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

Success Response (200 OK):

{
  "placeId": "ChIJOwg_06VPwokRYv534QaPC8g",
  "name": "Istanbul",
  "city": "Istanbul",
  "countryCode": "TR",
  "timezone": "Europe/Istanbul",
  "point": {
    "lat": 41.0082,
    "lon": 28.9784
  }
}

Response Fields

FieldTypeDescription
placeIdstringUnique place identifier
namestringLocation name
citystringCity name
countryCodestringISO country code (2 characters)
timezonestringIANA timezone identifier
pointobjectGeographic coordinates
point.latnumberLatitude coordinate
point.lonnumberLongitude coordinate

Location Search Best Practices

Query Optimization

  • Minimum Length: Queries must be at least 2 characters long
  • Language Support: The service supports multiple languages including Turkish and English
  • Fuzzy Matching: The search supports partial and fuzzy matching for better user experience
  • Special Characters: Handle special characters and diacritics appropriately

Autocomplete Implementation

  • Debouncing: Implement debouncing to avoid excessive API calls during typing
  • Caching: Cache recent search results to improve performance
  • Progressive Enhancement: Show results as the user types with progressive refinement
  • Keyboard Navigation: Support keyboard navigation for accessibility

Location Selection

  • Place ID Usage: Always use place IDs for location identification, not coordinates
  • Validation: Validate selected locations before proceeding to vehicle search
  • Fallback: Provide fallback options for locations that may not support car rentals
  • Favorites: Consider implementing location favorites for frequent users

Integration Examples

Autocomplete Implementation

class LocationAutocomplete {
    constructor(inputElement, apiToken) {
        this.input = inputElement;
        this.token = apiToken;
        this.debounceTimer = null;
        this.cache = new Map();

        this.setupEventListeners();
    }

    setupEventListeners() {
        this.input.addEventListener('input', (e) => {
            this.handleInput(e.target.value);
        });
    }

    handleInput(query) {
        // Clear previous timer
        clearTimeout(this.debounceTimer);

        // Validate minimum length
        if (query.length < 2) {
            this.clearResults();
            return;
        }

        // Debounce the search
        this.debounceTimer = setTimeout(() => {
            this.searchLocations(query);
        }, 300);
    }

    async searchLocations(query) {
        // Check cache first
        if (this.cache.has(query)) {
            this.displayResults(this.cache.get(query));
            return;
        }

        try {
            const response = await fetch(
                `/api/v1/locations?query=${encodeURIComponent(query)}`,
                {
                    headers: {
                        'Authorization': `Bearer ${this.token}`
                    }
                }
            );

            if (!response.ok) {
                throw new Error('Search failed');
            }

            const locations = await response.json();

            // Cache the results
            this.cache.set(query, locations);

            // Display results
            this.displayResults(locations);

        } catch (error) {
            console.error('Location search error:', error);
            this.showError('Failed to search locations');
        }
    }

    displayResults(locations) {
        // Implementation for displaying search results
        const resultsContainer = document.getElementById('location-results');
        resultsContainer.innerHTML = '';

        locations.forEach(location => {
            const item = document.createElement('div');
            item.className = 'location-item';
            item.innerHTML = `
        <div class="main-text">${location.mainText}</div>
        <div class="secondary-text">${location.secondaryText}</div>
      `;

            item.addEventListener('click', () => {
                this.selectLocation(location);
            });

            resultsContainer.appendChild(item);
        });
    }

    async selectLocation(location) {
        try {
            // Get detailed location information
            const response = await fetch(
                `/api/v1/locations/${location.placeId}`,
                {
                    headers: {
                        'Authorization': `Bearer ${this.token}`
                    }
                }
            );

            if (!response.ok) {
                throw new Error('Failed to get location details');
            }

            const locationDetails = await response.json();

            // Update input and trigger selection event
            this.input.value = location.description;
            this.input.dispatchEvent(new CustomEvent('locationSelected', {
                detail: locationDetails
            }));

            this.clearResults();

        } catch (error) {
            console.error('Location selection error:', error);
            this.showError('Failed to select location');
        }
    }

    clearResults() {
        const resultsContainer = document.getElementById('location-results');
        if (resultsContainer) {
            resultsContainer.innerHTML = '';
        }
    }

    showError(message) {
        // Implementation for showing error messages
        console.error(message);
    }
}

// Usage
const pickupInput = document.getElementById('pickup-location');
const autocomplete = new LocationAutocomplete(pickupInput, accessToken);

pickupInput.addEventListener('locationSelected', (event) => {
    const location = event.detail;
    console.log('Selected location:', location);

    // Store coordinates for vehicle search
    window.pickupCoordinates = {
        lat: location.point.lat,
        lon: location.point.lon
    };
});

Location Validation

async function validateLocation(placeId) {
    try {
        const response = await fetch(`/api/v1/locations/${placeId}`, {
            headers: {
                'Authorization': `Bearer ${accessToken}`
            }
        });

        if (!response.ok) {
            if (response.status === 404) {
                throw new Error('Location not found or not supported');
            }
            throw new Error('Location validation failed');
        }

        const location = await response.json();

        // Validate that location has required fields
        if (!location.point || !location.point.lat || !location.point.lon) {
            throw new Error('Location does not have valid coordinates');
        }

        return location;

    } catch (error) {
        console.error('Location validation error:', error);
        throw error;
    }
}

Location Comparison

function calculateDistance(location1, location2) {
    const R = 6371; // Earth's radius in kilometers
    const dLat = (location2.lat - location1.lat) * Math.PI / 180;
    const dLon = (location2.lon - location1.lon) * Math.PI / 180;

    const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(location1.lat * Math.PI / 180) * Math.cos(location2.lat * Math.PI / 180) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);

    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    const distance = R * c;

    return distance; // Distance in kilometers
}

function validateLocationDistance(pickupLocation, dropoffLocation) {
    const distance = calculateDistance(
        pickupLocation.point,
        dropoffLocation.point
    );

    // Warn if locations are very far apart (>500km)
    if (distance > 500) {
        return {
            valid: true,
            warning: `Pickup and drop-off locations are ${distance.toFixed(0)}km apart`
        };
    }

    return {valid: true};
}

Error Handling

Common Error Responses

  • 400 Bad Request: Invalid query parameter or missing required fields
  • 401 Unauthorized: Authentication required or token expired
  • 404 Not Found: Place ID not found or location not supported
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Service temporarily unavailable

Example Error Response

{
  "code": 1001,
  "description": "Invalid query parameter",
  "details": {
    "field": "query",
    "message": "Query must be at least 2 characters long"
  }
}

Error Handling Best Practices

  • Graceful Degradation: Provide fallback options when location search fails
  • User Feedback: Show clear error messages to users
  • Retry Logic: Implement exponential backoff for temporary failures
  • Validation: Validate user input before making API calls

Performance Considerations

Caching Strategy

  • Search Results: Cache search results for identical queries
  • Location Details: Cache detailed location information
  • TTL: Use appropriate time-to-live values (suggested: 1 hour for search, 24 hours for details)
  • Storage: Use browser localStorage or sessionStorage for client-side caching

Rate Limiting

Location endpoints are subject to rate limiting:

  • Search endpoint: Maximum 60 requests per minute per user
  • Details endpoint: Maximum 100 requests per minute per user

Optimization Tips

  • Debouncing: Use 300ms debounce for search input
  • Batch Requests: If possible, batch location detail requests
  • Preloading: Preload popular locations for faster response
  • CDN: Use CDN for static location data if available

Accessibility Considerations

  • Keyboard Navigation: Support arrow keys for result navigation
  • Screen Readers: Provide appropriate ARIA labels and descriptions
  • Focus Management: Manage focus properly during location selection
  • Voice Input: Support voice input for location search
  • High Contrast: Ensure location results are visible in high contrast mode