# 📱 راهنمای یکپارچه‌سازی کلاینت ## نگاه کلی این راهنما برای توسعه‌دهندگان Frontend است که می‌خواهند از API های پروژه استفاده کنند. --- ## 🎯 پشتیبانی از Client Applications ### ✅ پلتفرم‌های پشتیبانی شده: ``` ✅ Web (JavaScript/TypeScript) ✅ React / Next.js ✅ Vue.js ✅ Angular ✅ Mobile (React Native) ✅ iOS (Swift) ✅ Android (Kotlin/Java) ✅ Desktop (Electron) ✅ Python Scripts ✅ Any HTTP/WebSocket Client ``` --- ## 🔌 روش‌های اتصال ### 1. REST API (HTTP/HTTPS) **Base URL:** ``` Development: http://localhost:7860 Production: https://your-domain.com ``` **Headers مورد نیاز:** ```http Content-Type: application/json Accept: application/json Origin: https://your-domain.com (برای CORS) ``` **Headers اختیاری:** ```http Authorization: Bearer YOUR_TOKEN (برای endpoints محافظت شده) X-Client-Version: 1.0.0 User-Agent: YourApp/1.0 ``` --- ### 2. WebSocket (Real-time) **URLs:** ``` ws://localhost:7860/ws/master ws://localhost:7860/ws/market_data ws://localhost:7860/ws/news wss://your-domain.com/ws/... (برای HTTPS) ``` **Protocol:** - JSON-based messaging - Subscribe/Unsubscribe patterns - Auto-reconnect recommended --- ## 📚 نمونه کدها ### JavaScript/TypeScript #### Basic HTTP Request: ```typescript // استفاده از fetch API async function getBTCPrice(): Promise { try { const response = await fetch('http://localhost:7860/api/resources/market/price/BTC'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data.price; } catch (error) { console.error('Error fetching BTC price:', error); throw error; } } // استفاده const price = await getBTCPrice(); console.log(`BTC Price: $${price}`); ``` #### با Axios: ```typescript import axios from 'axios'; const API_BASE = 'http://localhost:7860'; // تنظیم instance const apiClient = axios.create({ baseURL: API_BASE, timeout: 10000, headers: { 'Content-Type': 'application/json' } }); // قیمت BTC export async function getBTCPrice() { const { data } = await apiClient.get('/api/resources/market/price/BTC'); return data.price; } // قیمت چندتا ارز export async function getMultiplePrices(symbols: string[]) { const { data } = await apiClient.get('/api/resources/market/prices', { params: { symbols: symbols.join(',') } }); return data.data; } // اخبار export async function getLatestNews(limit = 20) { const { data } = await apiClient.get('/api/resources/news/latest', { params: { limit } }); return data.news; } ``` --- ### React Hook ```typescript import { useState, useEffect } from 'react'; import axios from 'axios'; interface PriceData { symbol: string; price: number; source: string; timestamp: string; } export function useCryptoPrice(symbol: string, refreshInterval = 5000) { const [price, setPrice] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchPrice = async () => { try { setLoading(true); const { data } = await axios.get( `http://localhost:7860/api/resources/market/price/${symbol}` ); setPrice(data); setError(null); } catch (err: any) { setError(err.message); } finally { setLoading(false); } }; // اولین بار fetchPrice(); // Polling برای بروزرسانی const interval = setInterval(fetchPrice, refreshInterval); return () => clearInterval(interval); }, [symbol, refreshInterval]); return { price, loading, error }; } // استفاده در کامپوننت function BTCPriceDisplay() { const { price, loading, error } = useCryptoPrice('BTC'); if (loading) return
Loading...
; if (error) return
Error: {error}
; return (

Bitcoin Price

${price?.price.toLocaleString()}

Source: {price?.source}
); } ``` --- ### WebSocket در React ```typescript import { useEffect, useState } from 'react'; interface MarketUpdate { symbol: string; price: number; change: number; timestamp: string; } export function useWebSocket(url: string) { const [data, setData] = useState(null); const [connected, setConnected] = useState(false); const [ws, setWs] = useState(null); useEffect(() => { const websocket = new WebSocket(url); websocket.onopen = () => { console.log('WebSocket connected'); setConnected(true); // Subscribe به market data websocket.send(JSON.stringify({ action: 'subscribe', service: 'market_data' })); }; websocket.onmessage = (event) => { const message = JSON.parse(event.data); if (message.type === 'market_update') { setData(message.data); } }; websocket.onerror = (error) => { console.error('WebSocket error:', error); }; websocket.onclose = () => { console.log('WebSocket disconnected'); setConnected(false); // Auto-reconnect بعد از 5 ثانیه setTimeout(() => { console.log('Attempting to reconnect...'); // Recreate WebSocket }, 5000); }; setWs(websocket); return () => { websocket.close(); }; }, [url]); const sendMessage = (message: any) => { if (ws && connected) { ws.send(JSON.stringify(message)); } }; return { data, connected, sendMessage }; } // استفاده function LivePriceDisplay() { const { data, connected } = useWebSocket('ws://localhost:7860/ws/market_data'); return (
Status: {connected ? '🟢 Connected' : '🔴 Disconnected'}
{data && (

{data.symbol}

${data.price}

= 0 ? 'green' : 'red'}> {data.change >= 0 ? '+' : ''}{data.change}%

)}
); } ``` --- ### Vue.js Composable ```typescript // composables/useCryptoAPI.ts import { ref, onMounted, onUnmounted } from 'vue'; import axios from 'axios'; export function useCryptoPrice(symbol: string) { const price = ref(null); const loading = ref(true); const error = ref(null); let intervalId: number; const fetchPrice = async () => { try { loading.value = true; const { data } = await axios.get( `http://localhost:7860/api/resources/market/price/${symbol}` ); price.value = data; error.value = null; } catch (err: any) { error.value = err.message; } finally { loading.value = false; } }; onMounted(() => { fetchPrice(); intervalId = setInterval(fetchPrice, 5000); }); onUnmounted(() => { clearInterval(intervalId); }); return { price, loading, error }; } // استفاده در component ``` --- ### Python Client ```python import requests import asyncio import websockets import json class CryptoAPIClient: """Python client برای Crypto API""" def __init__(self, base_url='http://localhost:7860'): self.base_url = base_url self.session = requests.Session() self.session.headers.update({ 'Content-Type': 'application/json', 'User-Agent': 'PythonClient/1.0' }) def get_price(self, symbol): """دریافت قیمت یک ارز""" response = self.session.get( f'{self.base_url}/api/resources/market/price/{symbol}' ) response.raise_for_status() return response.json() def get_multiple_prices(self, symbols): """دریافت قیمت چند ارز""" response = self.session.get( f'{self.base_url}/api/resources/market/prices', params={'symbols': ','.join(symbols)} ) response.raise_for_status() return response.json()['data'] def get_news(self, limit=20): """دریافت آخرین اخبار""" response = self.session.get( f'{self.base_url}/api/resources/news/latest', params={'limit': limit} ) response.raise_for_status() return response.json()['news'] def get_fear_greed_index(self): """دریافت شاخص ترس و طمع""" response = self.session.get( f'{self.base_url}/api/resources/sentiment/fear-greed' ) response.raise_for_status() return response.json() async def connect_websocket(self, on_message_callback): """اتصال به WebSocket""" uri = self.base_url.replace('http', 'ws') + '/ws/master' async with websockets.connect(uri) as websocket: # Subscribe await websocket.send(json.dumps({ 'action': 'subscribe', 'service': 'market_data' })) # دریافت پیام‌ها async for message in websocket: data = json.loads(message) await on_message_callback(data) # استفاده client = CryptoAPIClient() # REST API btc_price = client.get_price('BTC') print(f"BTC Price: ${btc_price['price']}") prices = client.get_multiple_prices(['BTC', 'ETH', 'BNB']) for price_data in prices: print(f"{price_data['symbol']}: ${price_data['price']}") # WebSocket async def handle_message(data): print(f"Received: {data}") asyncio.run(client.connect_websocket(handle_message)) ``` --- ### React Native ```typescript import { useEffect, useState } from 'react'; import { View, Text, ActivityIndicator } from 'react-native'; export function PriceScreen() { const [price, setPrice] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchPrice = async () => { try { const response = await fetch( 'http://your-api.com/api/resources/market/price/BTC' ); const data = await response.json(); setPrice(data.price); } catch (error) { console.error(error); } finally { setLoading(false); } }; fetchPrice(); const interval = setInterval(fetchPrice, 5000); return () => clearInterval(interval); }, []); if (loading) { return ; } return ( BTC Price ${price} ); } ``` --- ## 🔒 Authentication (در صورت نیاز) ### JWT Token Based: ```typescript // دریافت توکن (login) async function login(username: string, password: string) { const response = await fetch('http://localhost:7860/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await response.json(); // ذخیره توکن localStorage.setItem('token', data.token); return data.token; } // استفاده از توکن در درخواست‌ها async function getProtectedData() { const token = localStorage.getItem('token'); const response = await fetch('http://localhost:7860/api/protected/data', { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); return response.json(); } ``` --- ## ⚡ بهینه‌سازی Performance ### 1. Caching در Client: ```typescript class CachedAPIClient { private cache = new Map(); private cacheTTL = 5000; // 5 seconds async get(url: string) { const cached = this.cache.get(url); // بررسی cache if (cached && Date.now() - cached.timestamp < this.cacheTTL) { return cached.data; } // درخواست جدید const response = await fetch(url); const data = await response.json(); // ذخیره در cache this.cache.set(url, { data, timestamp: Date.now() }); return data; } } ``` ### 2. Request Batching: ```typescript class BatchedAPIClient { private pendingRequests: Map> = new Map(); async get(url: string) { // اگر همین درخواست در حال انجام است، همان را برگردان if (this.pendingRequests.has(url)) { return this.pendingRequests.get(url); } // درخواست جدید const promise = fetch(url).then(r => r.json()); this.pendingRequests.set(url, promise); try { const data = await promise; return data; } finally { this.pendingRequests.delete(url); } } } ``` ### 3. Debouncing: ```typescript function debounce any>( func: T, wait: number ): (...args: Parameters) => void { let timeout: NodeJS.Timeout; return function executedFunction(...args: Parameters) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // استفاده const debouncedSearch = debounce(async (query: string) => { const results = await fetch(`/api/search?q=${query}`); // ... }, 300); // در input debouncedSearch(e.target.value)} /> ``` --- ## 🚨 Error Handling ### Retry Logic: ```typescript async function fetchWithRetry( url: string, options: RequestInit = {}, retries = 3, delay = 1000 ): Promise { try { const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return await response.json(); } catch (error) { if (retries > 0) { console.log(`Retrying... (${retries} attempts left)`); await new Promise(resolve => setTimeout(resolve, delay)); return fetchWithRetry(url, options, retries - 1, delay * 2); } throw error; } } ``` ### Global Error Handler: ```typescript class APIClient { async request(url: string, options?: RequestInit) { try { const response = await fetch(url, options); if (response.status === 401) { // Token منقضی شده await this.refreshToken(); return this.request(url, options); // Retry } if (response.status === 429) { // Rate limit const retryAfter = response.headers.get('Retry-After'); await new Promise(r => setTimeout(r, parseInt(retryAfter || '5') * 1000)); return this.request(url, options); // Retry } if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Request failed'); } return await response.json(); } catch (error) { // Log to monitoring service this.logError(error); throw error; } } } ``` --- ## 📊 Rate Limiting **سمت سرور:** ``` ✅ 100 requests/minute per IP ✅ Headers شامل rate limit info ``` **Response Headers:** ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1702027200 ``` **Handle در Client:** ```typescript async function checkRateLimit(response: Response) { const limit = response.headers.get('X-RateLimit-Limit'); const remaining = response.headers.get('X-RateLimit-Remaining'); const reset = response.headers.get('X-RateLimit-Reset'); if (response.status === 429) { const retryAfter = parseInt(reset!) - Date.now() / 1000; throw new Error(`Rate limit exceeded. Retry after ${retryAfter}s`); } return { limit: parseInt(limit!), remaining: parseInt(remaining!), reset: new Date(parseInt(reset!) * 1000) }; } ``` --- ## ✅ Best Practices ### 1. همیشه Error Handling داشته باشید ```typescript try { const data = await apiCall(); } catch (error) { // Handle error console.error(error); showErrorToUser(error.message); } ``` ### 2. Timeout تنظیم کنید ```typescript const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 10000); fetch(url, { signal: controller.signal }) .finally(() => clearTimeout(timeout)); ``` ### 3. Loading States نشان دهید ```typescript const [loading, setLoading] = useState(false); setLoading(true); try { await apiCall(); } finally { setLoading(false); } ``` ### 4. Cache استفاده کنید ```typescript // React Query const { data } = useQuery('prices', fetchPrices, { staleTime: 5000, cacheTime: 10000 }); ``` --- ## 📱 پلتفرم‌های خاص ### iOS (Swift): ```swift import Foundation class CryptoAPIClient { let baseURL = "http://localhost:7860" func getPrice(symbol: String, completion: @escaping (Result) -> Void) { guard let url = URL(string: "\(baseURL)/api/resources/market/price/\(symbol)") else { return } URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(error)) return } guard let data = data else { return } do { let json = try JSONDecoder().decode(PriceResponse.self, from: data) completion(.success(json.price)) } catch { completion(.failure(error)) } }.resume() } } struct PriceResponse: Codable { let price: Double let symbol: String } ``` ### Android (Kotlin): ```kotlin import retrofit2.http.GET import retrofit2.http.Path interface CryptoAPI { @GET("api/resources/market/price/{symbol}") suspend fun getPrice(@Path("symbol") symbol: String): PriceResponse } data class PriceResponse( val price: Double, val symbol: String, val source: String ) // استفاده val api = Retrofit.Builder() .baseUrl("http://localhost:7860") .addConverterFactory(GsonConverterFactory.create()) .build() .create(CryptoAPI::class.java) lifecycleScope.launch { val response = api.getPrice("BTC") println("BTC Price: ${response.price}") } ``` --- **تاریخ بروزرسانی**: ۸ دسامبر ۲۰۲۵ **نسخه**: ۱.۰ **وضعیت**: ✅ تکمیل شده