# Frontend'de Axios ile API tüketmek

> Axios kütüphanesiyle istek/yanıt katmanını arayüzde temiz tutmak için interceptor, hata yönetimi ve ortak yapılandırma üzerine pratik notlar.

- Yayın: 2018-11-04
- Kategori: Arayüz
- Etiketler: JavaScript
- Okuma süresi: 4 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/frontendde-axios-ile-api-tuketmek/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
Vue projelerinde API isteklerini ele almak için bir süre ham `fetch` API'sini kullandım. Çalışıyor, tarayıcıya dahil, ekstra bağımlılık yok. Ama her istekte aynı başlıkları tekrar yazmak, JSON parse etmeyi elle yapmak ve hataları her yerde ayrı ayrı ele almak kodu gereksiz yere şişiriyordu. Axios'a geçtikten sonra bu tekrarlar ortadan kalktı.

## Axios nedir?

**Axios**, [Promise](/blog/javascriptte-promise-ve-asenkron-akis) tabanlı bir HTTP istemcisidir. Tarayıcıda `XMLHttpRequest`, Node.js tarafında `http` modülü üzerine inşa edilmiş; her iki ortamda da aynı arayüzle çalışıyor. Otomatik JSON dönüşümü, istek iptali ve interceptor desteği gibi özellikleri ham `fetch` API'sinin üstüne koyuyor.

Kurulumu basit:

```bash
npm install axios
```

## Temel kullanım

```javascript
import axios from 'axios'

// GET isteği
axios.get('/api/users')
  .then(response => {
    console.log(response.data)
  })
  .catch(error => {
    console.error(error)
  })

// POST isteği
axios.post('/api/users', {
  name: 'Muhammet',
  email: 'muhammet@example.com'
})
  .then(response => console.log(response.data))
```

`response.data` doğrudan JSON nesnesine erişimi sağlıyor; elle `.json()` çağırmak gerekmiyor. Bu küçük ama sürekli kullanıldığında hissedilen bir rahatlama.

## Ortak yapılandırma: axios instance

Her istekte temel URL'yi, yetkilendirme başlığını tekrar yazmamak için özelleştirilmiş bir Axios instance'ı oluşturmak iyi bir alışkanlık:

```javascript
// src/api/client.js

import axios from 'axios'

const apiClient = axios.create({
  baseURL: process.env.VUE_APP_API_URL || '/api',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  }
})

export default apiClient
```

Artık tüm isteklerde bu `apiClient`'ı içe aktarıyorsunuz; `/api` öneki, başlıklar ve timeout otomatik geliyor.

## Interceptor ile merkezi işlem

**Interceptor**, istek gönderilmeden önce ya da yanıt alındıktan sonra devreye giren bir ara işlemdir. Yetkilendirme token'ını eklemek ya da hataları merkezi olarak yakalamak için idealdir.

İstek interceptor'u örneği:

```javascript
apiClient.interceptors.request.use(
  config => {
    const token = localStorage.getItem('auth_token')
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  },
  error => Promise.reject(error)
)
```

Her istek bu interceptor'dan geçtiği için token eklemeyi her istek noktasında tekrar yazmak gerekmiyor.

Yanıt interceptor'u örneği — 401 durumunda oturumu sonlandırmak:

```javascript
apiClient.interceptors.response.use(
  response => response,
  error => {
    if (error.response && error.response.status === 401) {
      // Token geçersiz; oturum temizle, giriş sayfasına yönlendir
      localStorage.removeItem('auth_token')
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)
```

Bu iki interceptor ile yetkilendirme ve oturum yönetiminin merkezi noktası tek bir dosyada toplandı.

## İstek modüllerini ayırmak

Axios instance'ı hazır; sonraki adım API çağrılarını bileşenlerden ayırmak. Her kaynak için ayrı bir modül yazmak bu işi temizleştiriyor:

```javascript
// src/api/users.js

import apiClient from './client'

export const getUsers = () => apiClient.get('/users')
export const getUser  = (id) => apiClient.get(`/users/${id}`)
export const createUser = (data) => apiClient.post('/users', data)
export const updateUser = (id, data) => apiClient.put(`/users/${id}`, data)
export const deleteUser = (id) => apiClient.delete(`/users/${id}`)
```

Vue bileşeninde kullanım:

```javascript
import { getUsers } from '@/api/users'

export default {
  data() {
    return { users: [] }
  },
  async created() {
    try {
      const response = await getUsers()
      this.users = response.data
    } catch (error) {
      console.error('Kullanıcılar yüklenemedi', error)
    }
  }
}
```

[Bileşen](/blog/vue-ile-bilesen-tabanli-arayuz-mimarisine-gecis), Axios'tan haberdar değil. Sadece `getUsers` fonksiyonunu çağırıyor. API'nin hangi kütüphaneyle tüketildiğini değiştirmeniz gerekirse yalnızca `src/api/users.js` değişiyor.

## Hata durumlarını ele almak

Axios, HTTP hata durumlarında (4xx, 5xx) otomatik olarak Promise'i reddediyor. `catch` bloğunda `error.response` varlığını kontrol ederek sunucu hatası mı, ağ hatası mı olduğunu ayırt edebilirsiniz:

```javascript
try {
  await createUser(data)
} catch (error) {
  if (error.response) {
    // Sunucu yanıt verdi ama 2xx dışı bir durum kodu döndürdü
    console.error('Sunucu hatası:', error.response.status)
  } else if (error.request) {
    // İstek gönderildi ama yanıt alınamadı (ağ sorunu)
    console.error('Ağ hatası')
  } else {
    // İstek oluşturulurken hata oluştu
    console.error('İstek hatası:', error.message)
  }
}
```

## fetch ile karşılaştırma

Ham `fetch` kullananlar için bir not: `fetch`, 4xx ve 5xx yanıtlarda Promise'i reddetmez — `response.ok` kontrolünü kendiniz yapmak gerekir. Axios bu davranışı tersine çevirdiği için hata yönetimi `catch`'e konsolide oluyor. Hangi yaklaşımı tercih edeceğiniz kişisel tercih meselesi, ama interceptor'lara ve otomatik JSON dönüşümüne ihtiyacınız varsa Axios bir adım öne çıkıyor. Ekstra bağımlılık eklemek istemiyorsanız ve basit bir proje söz konusuysa `fetch` de yeterli.

## Sonuç

Axios'u doğrudan bileşenlere gömmek yerine ayrı bir API katmanı olarak yapılandırmak, frontend kodunu bakımı kolay tutuyor. Interceptor'lar merkezi işlemleri tek yere topluyor; modüler yapı ise bileşenleri HTTP kütüphanesinden bağımsız kılıyor. Bu katmanı oturtmak başlangıçta birkaç ekstra dosya demek ama proje büyüdükçe bu yatırım değerini gösteriyor.

Son olarak bir tuzak: interceptor zincirinde unhandled rejection bırakmak sorun çıkarabiliyor. Yanıt interceptor'unda `return Promise.reject(error)` yazmayı unutursanız, hata yutulmuş oluyor ve bileşendeki `catch` bloğu hiç tetiklenmiyor. Özellikle 401 yönlendirmesi eklenirken bu satırın eksik kalması, kullanıcıyı giriş sayfasına yönlendiriyor ama bileşenin hata durumunu işlememesine neden oluyor. Interceptor yazarken her kod yolunun bir değer ya da reddedilmiş Promise döndürdüğünden emin olmak önemli.
