📱 راهنمای یکپارچهسازی کلاینت
نگاه کلی
این راهنما برای توسعهدهندگان 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 مورد نیاز:
Content-Type: application/json
Accept: application/json
Origin: https://your-domain.com (برای CORS)
Headers اختیاری:
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:
// استفاده از fetch API
async function getBTCPrice(): Promise<number> {
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:
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
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<PriceData | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(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 <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h2>Bitcoin Price</h2>
<p>${price?.price.toLocaleString()}</p>
<small>Source: {price?.source}</small>
</div>
);
}
WebSocket در React
import { useEffect, useState } from 'react';
interface MarketUpdate {
symbol: string;
price: number;
change: number;
timestamp: string;
}
export function useWebSocket(url: string) {
const [data, setData] = useState<MarketUpdate | null>(null);
const [connected, setConnected] = useState(false);
const [ws, setWs] = useState<WebSocket | null>(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 (
<div>
<div>Status: {connected ? '🟢 Connected' : '🔴 Disconnected'}</div>
{data && (
<div>
<h3>{data.symbol}</h3>
<p>${data.price}</p>
<p className={data.change >= 0 ? 'green' : 'red'}>
{data.change >= 0 ? '+' : ''}{data.change}%
</p>
</div>
)}
</div>
);
}
Vue.js Composable
// 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
<script setup>
import { useCryptoPrice } from '@/composables/useCryptoAPI';
const { price, loading, error } = useCryptoPrice('BTC');
</script>
<template>
<div>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else>
<h2>{{ price.symbol }}</h2>
<p>${{ price.price }}</p>
</div>
</div>
</template>
Python Client
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
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 <ActivityIndicator />;
}
return (
<View>
<Text>BTC Price</Text>
<Text>${price}</Text>
</View>
);
}
🔒 Authentication (در صورت نیاز)
JWT Token Based:
// دریافت توکن (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:
class CachedAPIClient {
private cache = new Map<string, { data: any; timestamp: number }>();
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:
class BatchedAPIClient {
private pendingRequests: Map<string, Promise<any>> = 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:
function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout;
return function executedFunction(...args: Parameters<T>) {
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
<input onChange={(e) => debouncedSearch(e.target.value)} />
🚨 Error Handling
Retry Logic:
async function fetchWithRetry(
url: string,
options: RequestInit = {},
retries = 3,
delay = 1000
): Promise<any> {
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:
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:
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 داشته باشید
try {
const data = await apiCall();
} catch (error) {
// Handle error
console.error(error);
showErrorToUser(error.message);
}
2. Timeout تنظیم کنید
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
fetch(url, { signal: controller.signal })
.finally(() => clearTimeout(timeout));
3. Loading States نشان دهید
const [loading, setLoading] = useState(false);
setLoading(true);
try {
await apiCall();
} finally {
setLoading(false);
}
4. Cache استفاده کنید
// React Query
const { data } = useQuery('prices', fetchPrices, {
staleTime: 5000,
cacheTime: 10000
});
📱 پلتفرمهای خاص
iOS (Swift):
import Foundation
class CryptoAPIClient {
let baseURL = "http://localhost:7860"
func getPrice(symbol: String, completion: @escaping (Result<Double, Error>) -> 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):
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}")
}
تاریخ بروزرسانی: ۸ دسامبر ۲۰۲۵
نسخه: ۱.۰
وضعیت: ✅ تکمیل شده