nodesty-api-library 1.0.1
nodesty.com için Python API istemci kütüphanesi
Requires Python: >=3.9

# Nodesty Python API Client

[![API](https://img.shields.io/badge/Nodesty-API-green.svg)](https://nodesty.com)
[![Python](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://python.org)
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PyPI](https://img.shields.io/pypi/v/nodesty-api-client.svg)](https://pypi.org/project/nodesty-api-library/1.0.0/)
[![Author](https://img.shields.io/badge/Author--RED.svg)](https://github.com/staticius)

nodesty.com'un güçlü API'sine Python uygulamalarınızdan kolayca erişmenizi sağlayan modern, asenkron ve tip güvenli bir istemci kütüphanesi. httpx ve pydantic kütüphanelerinin gücünü kullanarak API etkileşimlerinizi basitleştirir.

## 🚀 Özellikler

- **⚡ Asenkron Operasyonlar**: `httpx` ile tam async destek
- **🔒 Tip Güvenliği**: `pydantic` ile güçlü veri modelleri ve doğrulama
- **🔄 Otomatik Serileştirme**: JSON ↔ Python veri tipleri dönüşümü
- **⚙️ Yapılandırılabilir**: Timeout, retry, rate limit ayarları
- **🛡️ Kapsamlı Hata Yönetimi**: Standart `ApiResponse<T>` yapısı
- **📦 Modüler Yapı**: Her servis kendi modülü içinde

## 📋 Desteklenen Servisler

| Servis | Açıklama | Erişim |
|-----------------------|-----------------------------------------------------------|---------------------------|
| **User Service** | Kullanıcı profili, hizmetler, faturalar, destek biletleri | `client.user` |
| **VPS Service** | VPS yönetimi, yedekler, şifre değişimi, istatistikler | `client.vps` |
| **Dedicated Service** | Dedicated sunucu yönetimi, donanım bilgileri | `client.dedicated_server` |
| **Firewall Service** | nShield kuralları, saldırı logları, rDNS yönetimi | `client.firewall` |

## 🛠️ Kurulum

PyPI üzerinden pip ile kolayca kurabilirsiniz:

```bash
pip install nodesty-api-client
```

## 🔑 Başlangıç

### API Token Alma

1. [Nodesty kontrol paneli](https://nodesty.com/dashboard/my-account/access-tokens) adresine giriş yapın.

### Temel Kullanım

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions
from datetime import timedelta

async def main():
    token = os.environ.get("NODESTY_API_TOKEN")
    if not token:
        raise ValueError("NODESTY_API_TOKEN ortam değişkeni ayarlanmamış.")

    options = RestClientOptions(access_token=token)\
        .with_timeout(timedelta(seconds=45))\
        .with_retry(5)\
        .with_rate_limit_offset(timedelta(milliseconds=100))

    # Asenkron bağlam yöneticisi olarak NodestyApiClient'i kullanın
    async with NodestyApiClient(options) as client:
        user_response = await client.user.get_current_user()

        if user_response.success:
            if user_response.data:
                print(f"Hoş geldin {user_response.data.name}")
            else:
                print("Kullanıcı bilgisi bulunamadı.")
        else:
            print(f"Kullanıcı bilgisi getirilirken hata oluştu: {user_response.error}")

if __name__ == "__main__":
    asyncio.run(main())
```

## 📖 Kullanım Örnekleri

### 👤 Kullanıcı Bilgileri

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions

async def get_user_info():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)
    
    async with NodestyApiClient(options) as client:
        res = await client.user.get_current_user()
        if res.success and res.data:
            user = res.data
            print(f"Merhaba {user.full_name}")
            print(f"Email: {user.email}")
        else:
            print(f"Hata: {res.error}")

if __name__ == "__main__":
    asyncio.run(get_user_info())
```

### 🖥️ VPS Yönetimi

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions
from nodesty_api_client.models.vps import VpsAction

async def manage_vps():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)
    
    async with NodestyApiClient(options) as client:
        vps_id = "your-vps-id"

        # VPS'i yeniden başlat
        restart_res = await client.vps.perform_action(vps_id, VpsAction.RESTART)
        if restart_res.success:
            print(f"VPS {vps_id} başarıyla yeniden başlatıldı.")
        else:
            print(f"VPS yeniden başlatılırken hata oluştu: {restart_res.error}")

        # Yedekleri listele
        backups_res = await client.vps.get_backups(vps_id)
        if backups_res.success and backups_res.data:
            print("Yedekler:")
            for backup in backups_res.data:
                print(f"- Tarih: {backup.date}, Dosya: {backup.file}")
        else:
            print(f"Yedekler getirilirken hata oluştu: {backups_res.error}")

if __name__ == "__main__":
    asyncio.run(manage_vps())
```

### 🔧 Dedicated Sunucu

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions

async def get_dedicated_info():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)
    
    async with NodestyApiClient(options) as client:
        dedicated_id = "your-dedicated-id"
        res = await client.dedicated_server.get_hardware_components(dedicated_id)
        
        if res.success and res.data:
            print("Donanım Bileşenleri:")
            for part in res.data:
                print(f"- {part.component}: {part.model} {part.value}{part.value_suffix}")
        else:
            print(f"Donanım bileşenleri getirilirken hata oluştu: {res.error}")

if __name__ == "__main__":
    asyncio.run(get_dedicated_info())
```

### 🛡️ Güvenlik Duvarı

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions
from nodesty_api_client.models.firewall import FirewallCreateRuleData

async def manage_firewall():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)
    
    async with NodestyApiClient(options) as client:
        service_id = "your-service-id"
        ip_address = "your-ip-address"

        # Yeni bir kural oluştur
        rule_data = FirewallCreateRuleData(port=25565, app_id=123)
        create_res = await client.firewall.create_rule(service_id, ip_address, rule_data)
        
        if create_res.success:
            print("Güvenlik duvarı kuralı başarıyla oluşturuldu.")
        else:
            print(f"Kural oluşturulurken hata oluştu: {create_res.error}")

        # Saldırı kayıtlarını getir
        logs_res = await client.firewall.get_attack_logs(service_id, ip_address)
        if logs_res.success and logs_res.data:
            print("Saldırı Kayıtları:")
            for log in logs_res.data:
                print(f"- Başlangıç: {log.started_at}, Vektörler: {log.vectors}")
        else:
            print(f"Saldırı kayıtları getirilirken hata oluştu: {logs_res.error}")

if __name__ == "__main__":
    asyncio.run(manage_firewall())
```

## 🏗️ API Yanıt Yapısı

Tüm API çağrıları `ApiResponse<T>` döner:

```python
from typing import TypeVar, Generic, Optional
from pydantic import BaseModel

T = TypeVar('T')

class ApiResponse(BaseModel, Generic[T]):
    success: bool
    error: Optional[str] = None
    data: Optional[T] = None
```

## ⚙️ Yapılandırma Seçenekleri

```python
from nodesty_api_client import RestClientOptions
from datetime import timedelta

options = RestClientOptions(access_token="YOUR_API_TOKEN")\
    .with_timeout(timedelta(seconds=30))\
    .with_retry(3)\
    .with_rate_limit_offset(timedelta(milliseconds=50))
```

## 📚 API Servisleri

### 👤 User Service (`client.user`)

| Metod | Açıklama | Endpoint |
|----------------------|----------------------------|--------------------------------|
| `get_current_user()` | Kullanıcı profilini al | `GET /users/@me` |
| `get_services()` | Hizmetleri listele | `GET /services` |
| `get_tickets()` | Destek biletlerini listele | `GET /tickets` |
| `get_ticket_by_id(id)` | Belirli bileti getir | `GET /tickets/{id}` |
| `get_invoices()` | Faturaları listele | `GET /users/@me/invoices` |
| `get_invoice_by_id(id)` | Belirli faturayı getir | `GET /users/@me/invoices/{id}` |
| `get_sessions()` | Aktif oturumları getir | `GET /users/@me/sessions` |

### 🖥️ VPS Service (`client.vps`)

| Metod | Açıklama | Endpoint |
|----------------------------------|-------------------------|-------------------------------------------------|
| `perform_action(id, action)` | VPS eylemi gerçekleştir | `POST /services/{id}/vps/action` |
| `get_backups(id)` | Yedekleri getir | `GET /services/{id}/vps/backups` |
| `restore_backup(id, data)` | Geri yükleme yap | `POST /services/{id}/vps/backup/restore` |
| `change_password(id, data)` | Şifre değiştir | `POST /services/{id}/vps/change-password` |
| `get_graphs(id)` | İstatistikleri al | `GET /services/{id}/vps/graphs` |
| `get_details(id)` | VPS detayları | `GET /services/{id}/vps/info` |
| `get_os_templates(id)` | OS şablonlarını getir | `GET /services/{id}/vps/os-templates` |
| `reinstall(id, data)` | Yeniden kurulum | `POST /services/{id}/vps/reinstall` |
| `get_tasks(id)` | Görevleri getir | `GET /services/{id}/vps/tasks` |

### 🔧 Dedicated Service (`client.dedicated_server`)

| Metod | Açıklama | Endpoint |
|-------------------------------|-------------------|-------------------------------------------------|
| `perform_action(id, action)` | Eylem çalıştır | `POST /services/{id}/dedicated/action` |
| `get_hardware_components(id)` | Donanım detayları | `GET /services/{id}/dedicated/hardware` |
| `get_details(id)` | Sunucu bilgisi | `GET /services/{id}/dedicated/info` |
| `get_os_templates(id)` | OS şablonları | `GET /services/{id}/dedicated/os-templates` |
| `get_reinstall_status(id)` | Kurulum durumu | `GET /services/{id}/dedicated/reinstall-status` |
| `reinstall(id, data)` | Yeniden kur | `POST /services/{id}/dedicated/reinstall` |
| `get_tasks(id)` | Görevleri getir | `GET /services/{id}/dedicated/tasks` |

### 🛡️ Firewall Service (`client.firewall`)

| Metod | Açıklama | Endpoint |
|-----------------------------------------------------|------------------------------|--------------------------------------------------------|
| `get_attack_logs(id, ip)` | Saldırı kayıtlarını getir | `GET /services/{id}/firewall/{ip}/attack-logs` |
| `get_attack_notification_settings(id, ip)` | Bildirim ayarları | `GET /services/{id}/firewall/{ip}/attack-notification` |
| `update_attack_notification_settings(id, ip, data)` | Bildirim ayarlarını güncelle | `PUT /services/{id}/firewall/{ip}/attack-notification` |
| `delete_reverse_dns(id, ip)` | rDNS kaldır | `DELETE /services/{id}/firewall/{ip}/rdns` |
| `get_reverse_dns(id, ip)` | rDNS bilgisi | `GET /services/{id}/firewall/{ip}/rdns` |
| `upsert_reverse_dns(id, ip, rdns_data)` | rDNS ayarla | `PUT /services/{id}/firewall/{ip}/rdns` |
| `delete_rule(id, ip, rule_id)` | Kural sil | `DELETE /services/{id}/firewall/{ip}/rules/{rule_id}` |
| `get_rules(id, ip)` | Kuralları getir | `GET /services/{id}/firewall/{ip}/rules` |
| `create_rule(id, ip, data)` | Kural oluştur | `POST /services/{id}/firewall/{ip}/rules` |
| `get_statistics(id, ip)` | İstatistikleri getir | `GET /services/{id}/firewall/{ip}/stats` |

## 🔐 Güvenlik İpuçları

- API token'ınızı doğrudan kodda tutmayın. Ortam değişkenlerinden (env vars) veya güvenli bir yapılandırma dosyasından alın
- Her `ApiResponse` sonrası `.success` özelliğini kontrol edin
- Hataları uygun try-except blokları veya if-else yapılarıyla detaylı olarak yönetin

## 🚀 Performans Önerileri

- Asenkron işlemleri `asyncio.gather()` ile paralel çalıştırın
- Gecikmeleri azaltmak için `RestClientOptions` içinde timeout ve rate limit ayarlarını yapılandırın
- Uygulama başında `NodestyApiClient`'i bir kere oluşturun ve tüm uygulamanız boyunca tekrar kullanın (`async with` ifadesi ile otomatik kapanmasını sağlayabilirsiniz)

## 🧪 Test Örneği

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions

async def test_user_service():
    token = os.environ.get("NODESTY_TEST_TOKEN")
    if not token:
        raise ValueError("NODESTY_TEST_TOKEN ortam değişkeni ayarlanmamış.")

    options = RestClientOptions(access_token=token)
    async with NodestyApiClient(options) as client:
        response = await client.user.get_current_user()
        assert response.success, f"Test başarısız: {response.error}"
        assert response.data and "@" in response.data.email, "Kullanıcı bilgisi veya email bulunamadı."
        print("Kullanıcı servisi testi başarılı!")

if __name__ == "__main__":
    asyncio.run(test_user_service())
```

## 🐛 Sorun Giderme

**httpx.HTTPStatusError: 401 Unauthorized**
- API token'ınız geçersiz veya süresi dolmuş olabilir. Nodesty kontrol panelinden kontrol edin

**httpx.ConnectTimeout veya benzeri Timeout hataları**
- Ağ bağlantınızı ve `RestClientOptions` içindeki timeout süresini kontrol edin. Gerekirse artırın

**Too Many Requests (429 Hata)**
- API'nin rate limitine takılmış olabilirsiniz. `RestClientOptions` içindeki `rate_limit_offset` değerini artırın veya istekler arasında daha fazla bekleme süresi ekleyin

## 📝 Changelog

### v1.0.0
- İlk kararlı sürüm
- Tüm Nodesty API endpoint'leri için asenkron client
- httpx ve pydantic ile tip güvenli ve sağlam veri modelleri

## 🤝 Katkıda Bulunma

1. Bu depoyu (repository) fork'layın
2. Yeni bir özellik veya hata düzeltmesi için bir branch oluşturun (`git checkout -b feature/harika-ozellik`)
3. Değişikliklerinizi yapın ve commit'leyin
4. Remote deponuza push yapın
5. Bir Pull Request (PR) gönderin

## 🔗 Bağlantılar

- [Nodesty Website](https://nodesty.com)
- [API Dökümantasyonu](https://nodesty.com/docs)

## ⭐ Destek

Bu proje faydalı olduysa bir yıldız (⭐) vererek destekleyebilirsiniz!

---

**Made with ❤️ for Nodesty Community.**