# Konum İşlemleri

Konum endpoint'leri, araç kiralama işlemleri için kapsamlı konum arama ve coğrafi kodlama hizmetleri sağlar. Bu
endpoint'ler, kullanıcıların otomatik tamamlama işleviyle alış ve teslim konumlarını bulmalarını ve detaylı konum
bilgilerini almalarını sağlar.

## Konum Arama

Metin sorguları kullanarak araç kiralama konumlarını arayın. Bu endpoint otomatik tamamlama işlevi sağlar ve arama
sorgusuna uyan konum tahminlerini döndürerek geliştirilmiş kullanıcı deneyimi sunar.

### Endpoint

```
GET /locations?query={query}
```

### Kimlik Doğrulama

Bu endpoint kimlik doğrulama gerektirir. Authorization başlığında JWT erişim jetonunuzu ekleyin:

```
Authorization: Bearer ERIŞIM_JETONUNUZ
```

### Sorgu Parametreleri

| Parametre | Tür | Gerekli | Açıklama |
|  --- | --- | --- | --- |
| `query` | string | Evet | Arama sorgu metni (minimum 2 karakter) |


### Örnek İstek

```bash
curl -X GET "https://api.pro.yolcu360.com/api/v1/locations?query=istanbul" \
  -H "Authorization: Bearer ERIŞIM_JETONUNUZ"
```

### Yanıt

**Başarılı Yanıt (200 OK):**

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

### Yanıt Alanları

| Alan | Tür | Açıklama |
|  --- | --- | --- |
| `placeId` | string | Konum için benzersiz tanımlayıcı |
| `description` | string | Konumun tam açıklaması |
| `mainText` | string | Birincil konum metni (genellikle ad) |
| `secondaryText` | string | İkincil açıklayıcı metin (genellikle adres) |
| `types` | array | Konum türleri (ör. havalimanı, şehir, mahalle) |


### Konum Türleri

| Tür | Açıklama |
|  --- | --- |
| `airport` | Havalimanı konumları |
| `locality` | Şehir veya kasabalar |
| `neighborhood` | İlçe veya mahalleler |
| `establishment` | İş yerleri |
| `point_of_interest` | Önemli yerler veya ilgi çekici noktalar |
| `political` | İdari sınırlar |


## Konum Detaylarını Al

Yer kimliğini kullanarak belirli bir konum hakkında detaylı bilgi alın. Bu endpoint koordinatlar, saat dilimi ve idari
bilgiler dahil olmak üzere kapsamlı konum verileri sağlar.

### Endpoint

```
GET /locations/{placeId}
```

### Kimlik Doğrulama

Bu endpoint kimlik doğrulama gerektirir. Authorization başlığında JWT erişim jetonunuzu ekleyin.

### Yol Parametreleri

| Parametre | Tür | Gerekli | Açıklama |
|  --- | --- | --- | --- |
| `placeId` | string | Evet | Konum aramasından benzersiz yer tanımlayıcısı |


### Örnek İstek

```bash
curl -X GET https://api.pro.yolcu360.com/api/v1/locations/ChIJOwg_06VPwokRYv534QaPC8g \
  -H "Authorization: Bearer ERIŞIM_JETONUNUZ"
```

### Yanıt

**Başarılı Yanıt (200 OK):**

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

### Yanıt Alanları

| Alan | Tür | Açıklama |
|  --- | --- | --- |
| `placeId` | string | Benzersiz yer tanımlayıcısı |
| `name` | string | Konum adı |
| `city` | string | Şehir adı |
| `countryCode` | string | ISO ülke kodu (2 karakter) |
| `timezone` | string | IANA saat dilimi tanımlayıcısı |
| `point` | object | Coğrafi koordinatlar |
| `point.lat` | number | Enlem koordinatı |
| `point.lon` | number | Boylam koordinatı |


## Konum Arama En İyi Uygulamaları

### Sorgu Optimizasyonu

- **Minimum Uzunluk**: Sorgular en az 2 karakter uzunluğunda olmalı
- **Dil Desteği**: Servis Türkçe ve İngilizce dahil birden fazla dili destekler
- **Bulanık Eşleştirme**: Arama, daha iyi kullanıcı deneyimi için kısmi ve bulanık eşleştirmeyi destekler
- **Özel Karakterler**: Özel karakterleri ve aksan işaretlerini uygun şekilde işleyin


### Otomatik Tamamlama Uygulaması

- **Debouncing**: Yazma sırasında aşırı API çağrılarını önlemek için debouncing uygulayın
- **Önbelleğe Alma**: Performansı artırmak için son arama sonuçlarını önbelleğe alın
- **Aşamalı Geliştirme**: Kullanıcı yazarken aşamalı iyileştirme ile sonuçları gösterin
- **Klavye Navigasyonu**: Erişilebilirlik için klavye navigasyonunu destekleyin


### Konum Seçimi

- **Yer Kimliği Kullanımı**: Konum tanımlama için her zaman yer kimliklerini kullanın, koordinatları değil
- **Doğrulama**: Araç aramasına geçmeden önce seçilen konumları doğrulayın
- **Yedek Seçenekler**: Araç kiralamasını desteklemeyen konumlar için yedek seçenekler sağlayın
- **Favoriler**: Sık kullanıcılar için konum favorileri uygulamayı düşünün


## Entegrasyon Örnekleri

### Otomatik Tamamlama Uygulaması

```javascript
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) {
        // Önceki zamanlayıcıyı temizle
        clearTimeout(this.debounceTimer);

        // Minimum uzunluğu doğrula
        if (query.length < 2) {
            this.clearResults();
            return;
        }

        // Aramayı debounce et
        this.debounceTimer = setTimeout(() => {
            this.searchLocations(query);
        }, 300);
    }

    async searchLocations(query) {
        // Önce önbelleği kontrol et
        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('Arama başarısız');
            }

            const locations = await response.json();

            // Sonuçları önbelleğe al
            this.cache.set(query, locations);

            // Sonuçları göster
            this.displayResults(locations);

        } catch (error) {
            console.error('Konum arama hatası:', error);
            this.showError('Konum arama başarısız');
        }
    }

    displayResults(locations) {
        // Arama sonuçlarını göstermek için uygulama
        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 {
            // Detaylı konum bilgilerini al
            const response = await fetch(
                `/api/v1/locations/${location.placeId}`,
                {
                    headers: {
                        'Authorization': `Bearer ${this.token}`
                    }
                }
            );

            if (!response.ok) {
                throw new Error('Konum detayları alınamadı');
            }

            const locationDetails = await response.json();

            // Input'u güncelle ve seçim event'i tetikle
            this.input.value = location.description;
            this.input.dispatchEvent(new CustomEvent('locationSelected', {
                detail: locationDetails
            }));

            this.clearResults();

        } catch (error) {
            console.error('Konum seçimi hatası:', error);
            this.showError('Konum seçimi başarısız');
        }
    }

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

    showError(message) {
        // Hata mesajlarını göstermek için uygulama
        console.error(message);
    }
}

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

pickupInput.addEventListener('locationSelected', (event) => {
    const location = event.detail;
    console.log('Seçilen konum:', location);

    // Araç arama için koordinatları sakla
    window.pickupCoordinates = {
        lat: location.point.lat,
        lon: location.point.lon
    };
});
```

### Konum Doğrulama

```javascript
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('Konum bulunamadı veya desteklenmiyor');
            }
            throw new Error('Konum doğrulama başarısız');
        }

        const location = await response.json();

        // Konumun gerekli alanlara sahip olduğunu doğrula
        if (!location.point || !location.point.lat || !location.point.lon) {
            throw new Error('Konum geçerli koordinatlara sahip değil');
        }

        return location;

    } catch (error) {
        console.error('Konum doğrulama hatası:', error);
        throw error;
    }
}
```

### Konum Karşılaştırması

```javascript
function calculateDistance(location1, location2) {
    const R = 6371; // Dünya'nın yarıçapı kilometre cinsinden
    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; // Kilometre cinsinden mesafe
}

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

    // Konumlar çok uzaksa uyar (>500km)
    if (distance > 500) {
        return {
            valid: true,
            warning: `Alış ve teslim konumları ${distance.toFixed(0)}km uzaklıkta`
        };
    }

    return {valid: true};
}
```

## Hata İşleme

### Yaygın Hata Yanıtları

- `400 Bad Request`: Geçersiz sorgu parametresi veya eksik gerekli alanlar
- `401 Unauthorized`: Kimlik doğrulama gerekli veya jetonun süresi dolmuş
- `404 Not Found`: Yer kimliği bulunamadı veya konum desteklenmiyor
- `429 Too Many Requests`: Hız sınırı aşıldı
- `500 Internal Server Error`: Servis geçici olarak kullanılamıyor


### Örnek Hata Yanıtı

```json
{
  "code": 1001,
  "description": "Geçersiz sorgu parametresi",
  "details": {
    "field": "query",
    "message": "Sorgu en az 2 karakter uzunluğunda olmalı"
  }
}
```

### Hata İşleme En İyi Uygulamaları

- **Zarif Düşüş**: Konum arama başarısız olduğunda yedek seçenekler sağlayın
- **Kullanıcı Geri Bildirimi**: Kullanıcılara net hata mesajları gösterin
- **Yeniden Deneme Mantığı**: Geçici arızalar için üstel geri çekilme uygulayın
- **Doğrulama**: API çağrıları yapmadan önce kullanıcı girişini doğrulayın


## Performans Değerlendirmeleri

### Önbelleğe Alma Stratejisi

- **Arama Sonuçları**: Aynı sorgular için arama sonuçlarını önbelleğe alın
- **Konum Detayları**: Detaylı konum bilgilerini önbelleğe alın
- **TTL**: Uygun yaşam süresi değerleri kullanın (önerilen: arama için 1 saat, detaylar için 24 saat)
- **Depolama**: İstemci tarafı önbelleğe alma için browser localStorage veya sessionStorage kullanın


### Hız Sınırlama

Konum endpoint'leri hız sınırlamasına tabidir:

- **Arama endpoint'i**: Kullanıcı başına dakikada maksimum 60 istek
- **Detaylar endpoint'i**: Kullanıcı başına dakikada maksimum 100 istek


### Optimizasyon İpuçları

- **Debouncing**: Arama girişi için 300ms debounce kullanın
- **Toplu İstekler**: Mümkünse konum detay isteklerini toplu olarak yapın
- **Ön Yükleme**: Daha hızlı yanıt için popüler konumları ön yükleyin
- **CDN**: Mevcut olduğunda statik konum verileri için CDN kullanın


## Erişilebilirlik Değerlendirmeleri

- **Klavye Navigasyonu**: Sonuç navigasyonu için ok tuşlarını destekleyin
- **Ekran Okuyucuları**: Uygun ARIA etiketleri ve açıklamalar sağlayın
- **Odak Yönetimi**: Konum seçimi sırasında odağı düzgün yönetin
- **Ses Girişi**: Konum arama için ses girişini destekleyin
- **Yüksek Kontrast**: Konum sonuçlarının yüksek kontrast modunda görünür olduğundan emin olun