🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples de Réseau Web TypeScript
Exemples de réseau Web TypeScript incluant les requêtes HTTP, les connexions WebSocket et la communication API
💻 Utilitaires Réseau typescript
🟢 simple
⭐⭐
Fonctions utilitaires pour la manipulation d'URL, le traitement des chaînes de requête, la validation des requêtes et la surveillance du statut réseau
⏱️ 20 min
🏷️ typescript, web, networking, utilities
Prerequisites:
Basic TypeScript, URL API
// Web TypeScript Network Utilities Examples
// Utility functions for common networking tasks
// 1. URL Utilities
class UrlUtilities {
// Parse URL
static parse(url: string): URL {
return new URL(url);
}
// Build URL with query parameters
static buildUrl(baseUrl: string, params: Record<string, string | number>): string {
const url = new URL(baseUrl);
Object.entries(params).forEach(([key, value]) => {
url.searchParams.set(key, String(value));
});
return url.toString();
}
// Get query parameters from URL
static getQueryParams(url: string): Record<string, string> {
const urlObj = new URL(url);
const params: Record<string, string> = {};
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
return params;
}
// Update query parameters
static updateQueryParams(
url: string,
updates: Record<string, string | number | null>
): string {
const urlObj = new URL(url);
Object.entries(updates).forEach(([key, value]) => {
if (value === null) {
urlObj.searchParams.delete(key);
} else {
urlObj.searchParams.set(key, String(value));
}
});
return urlObj.toString();
}
// Remove query parameters
static removeQueryParams(url: string, keys: string[]): string {
const urlObj = new URL(url);
keys.forEach(key => urlObj.searchParams.delete(key));
return urlObj.toString();
}
// Check if URL is valid
static isValid(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
// Get domain from URL
static getDomain(url: string): string {
const urlObj = new URL(url);
return urlObj.hostname;
}
// Get path from URL
static getPath(url: string): string {
const urlObj = new URL(url);
return urlObj.pathname;
}
}
// 2. Query String Utilities
class QueryStringUtilities {
// Serialize object to query string
static stringify(obj: Record<string, any>): string {
const params = new URLSearchParams();
Object.entries(obj).forEach(([key, value]) => {
if (value !== null && value !== undefined) {
if (Array.isArray(value)) {
value.forEach(v => params.append(key, String(v)));
} else {
params.set(key, String(value));
}
}
});
return params.toString();
}
// Parse query string to object
static parse(queryString: string): Record<string, string | string[]> {
const params = new URLSearchParams(queryString);
const result: Record<string, string | string[]> = {};
params.forEach((value, key) => {
if (key in result) {
const existing = result[key];
if (Array.isArray(existing)) {
existing.push(value);
} else {
result[key] = [existing, value];
}
} else {
result[key] = value;
}
});
return result;
}
// Merge query strings
static merge(...queryStrings: string[]): string {
const mergedParams = new URLSearchParams();
queryStrings.forEach(qs => {
const params = new URLSearchParams(qs);
params.forEach((value, key) => {
mergedParams.append(key, value);
});
});
return mergedParams.toString();
}
}
// 3. Network Status Monitor
class NetworkStatusMonitor {
private isOnline: boolean = navigator.onLine;
private listeners: Array<(online: boolean) => void> = [];
constructor() {
this.setupEventListeners();
}
private setupEventListeners(): void {
window.addEventListener('online', () => {
this.isOnline = true;
this.notifyListeners(true);
});
window.addEventListener('offline', () => {
this.isOnline = false;
this.notifyListeners(false);
});
}
private notifyListeners(online: boolean): void {
this.listeners.forEach(listener => listener(online));
}
// Get current status
getStatus(): boolean {
return this.isOnline;
}
// Subscribe to status changes
subscribe(listener: (online: boolean) => void): () => void {
this.listeners.push(listener);
// Return unsubscribe function
return () => {
const index = this.listeners.indexOf(listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
};
}
// Wait for connection
async waitForConnection(timeout: number = 30000): Promise<boolean> {
if (this.isOnline) {
return true;
}
return new Promise((resolve) => {
const timeoutId = setTimeout(() => {
unsubscribe();
resolve(false);
}, timeout);
const unsubscribe = this.subscribe((online) => {
if (online) {
clearTimeout(timeoutId);
unsubscribe();
resolve(true);
}
});
});
}
}
// 4. Request Validation
class RequestValidator {
// Validate URL
static validateUrl(url: string): { valid: boolean; error?: string } {
if (!url) {
return { valid: false, error: 'URL is required' };
}
try {
new URL(url);
return { valid: true };
} catch (error) {
return { valid: false, error: 'Invalid URL format' };
}
}
// Validate HTTP method
static validateMethod(method: string): { valid: boolean; error?: string } {
const validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];
if (!validMethods.includes(method.toUpperCase())) {
return { valid: false, error: `Invalid HTTP method: ${method}` };
}
return { valid: true };
}
// Validate headers
static validateHeaders(headers: Record<string, string>): { valid: boolean; errors: string[] } {
const errors: string[] = [];
Object.entries(headers).forEach(([key, value]) => {
// Check for invalid characters in header name
if (/[^\w\-!#$%&'*+.^_`|~]/.test(key)) {
errors.push(`Invalid header name: ${key}`);
}
// Check header value
if (/[ -]/.test(value)) {
errors.push(`Invalid header value for: ${key}`);
}
});
return {
valid: errors.length === 0,
errors
};
}
// Validate request body
static validateBody(body: any, maxLength: number = 1024 * 1024): { valid: boolean; error?: string } {
const bodyString = JSON.stringify(body);
if (bodyString.length > maxLength) {
return { valid: false, error: `Request body too large (max ${maxLength} bytes)` };
}
try {
JSON.parse(bodyString);
return { valid: true };
} catch {
return { valid: false, error: 'Invalid JSON in request body' };
}
}
}
// 5. CORS Utilities
class CorsUtilities {
// Check if CORS is needed
static isCrossOrigin(url: string): boolean {
const targetOrigin = new URL(url).origin;
const currentOrigin = window.location.origin;
return targetOrigin !== currentOrigin;
}
// Build CORS request
static buildCorsRequest(url: string, options: RequestInit = {}): RequestInit {
return {
...options,
mode: 'cors',
headers: {
...(options.headers || {}),
'Content-Type': 'application/json'
}
};
}
// Check if preflight request is needed
static isPreflightRequired(method: string, headers?: Record<string, string>): boolean {
const nonSimpleMethods = ['PUT', 'DELETE', 'PATCH', 'CONNECT', 'TRACE', 'OPTIONS'];
if (nonSimpleMethods.includes(method.toUpperCase())) {
return true;
}
if (headers) {
const nonSimpleHeaders = ['X-Requested-With', 'X-HTTP-Method-Override'];
return Object.keys(headers).some(h =>
nonSimpleHeaders.some(nsh => h.toLowerCase().startsWith(nsh.toLowerCase()))
);
}
return false;
}
}
// 6. Request Retry Logic
class RequestRetryHandler {
// Retry with exponential backoff
static async retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
if (attempt < maxRetries) {
const delay = baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError!;
}
// Retry on specific status codes
static async retryOnStatus<T>(
fn: () => Promise<Response>,
retryStatuses: number[] = [408, 429, 500, 502, 503, 504],
maxRetries: number = 3
): Promise<Response> {
let lastResponse: Response;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fn();
lastResponse = response;
if (!retryStatuses.includes(response.status)) {
return response;
}
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
}
}
return lastResponse!;
}
}
// 7. Connection Pool Manager (for managing multiple concurrent requests)
class ConnectionPool {
private activeRequests: Set<Promise<any>> = new Set();
private maxConcurrent: number;
constructor(maxConcurrent: number = 6) {
this.maxConcurrent = maxConcurrent;
}
// Execute request with pool management
async execute<T>(fn: () => Promise<T>): Promise<T> {
// Wait if pool is full
while (this.activeRequests.size >= this.maxConcurrent) {
await Promise.race(this.activeRequests);
}
const request = fn().finally(() => {
this.activeRequests.delete(request);
});
this.activeRequests.add(request);
return request;
}
// Get pool size
get size(): number {
return this.activeRequests.size;
}
// Get available slots
get available(): number {
return this.maxConcurrent - this.activeRequests.size;
}
}
// 8. Network Request Logger
class NetworkRequestLogger {
private logs: Array<{
timestamp: number;
url: string;
method: string;
status?: number;
duration: number;
success: boolean;
}> = [];
// Log request
async logRequest<T>(
fn: () => Promise<T>,
url: string,
method: string = 'GET'
): Promise<T> {
const startTime = Date.now();
const timestamp = startTime;
try {
const result = await fn();
const duration = Date.now() - startTime;
this.logs.push({
timestamp,
url,
method,
status: 200,
duration,
success: true
});
return result;
} catch (error) {
const duration = Date.now() - startTime;
this.logs.push({
timestamp,
url,
method,
status: 0,
duration,
success: false
});
throw error;
}
}
// Get all logs
getLogs(): typeof this.logs {
return [...this.logs];
}
// Get failed requests
getFailedRequests(): typeof this.logs {
return this.logs.filter(log => !log.success);
}
// Get slow requests (above threshold)
getSlowRequests(threshold: number = 1000): typeof this.logs {
return this.logs.filter(log => log.duration > threshold);
}
// Get statistics
getStats(): {
total: number;
successful: number;
failed: number;
avgDuration: number;
slowest: number;
fastest: number;
} {
const successful = this.logs.filter(l => l.success).length;
const failed = this.logs.filter(l => !l.success).length;
const durations = this.logs.map(l => l.duration);
return {
total: this.logs.length,
successful,
failed,
avgDuration: durations.length ? durations.reduce((a, b) => a + b) / durations.length : 0,
slowest: durations.length ? Math.max(...durations) : 0,
fastest: durations.length ? Math.min(...durations) : 0
};
}
// Clear logs
clearLogs(): void {
this.logs = [];
}
}
// Usage Examples
async function demonstrateNetworkUtilities() {
console.log('=== Web TypeScript Network Utilities Examples ===\n');
// 1. URL utilities
console.log('--- 1. URL Utilities ---');
const url = 'https://example.com/api/users?page=1&limit=10';
console.log(`Parsed URL:`, UrlUtilities.parse(url));
console.log(`Domain:`, UrlUtilities.getDomain(url));
console.log(`Path:`, UrlUtilities.getPath(url));
console.log(`Query params:`, UrlUtilities.getQueryParams(url));
const updatedUrl = UrlUtilities.updateQueryParams(url, { page: 2, filter: 'active' });
console.log(`Updated URL:`, updatedUrl);
// 2. Query string utilities
console.log('\n--- 2. Query String Utilities ---');
const obj = { search: 'test', page: 1, filters: ['a', 'b'] };
const queryString = QueryStringUtilities.stringify(obj);
console.log(`Stringified:`, queryString);
const parsed = QueryStringUtilities.parse(queryString);
console.log(`Parsed:`, parsed);
// 3. Network status
console.log('\n--- 3. Network Status ---');
const monitor = new NetworkStatusMonitor();
console.log(`Currently online: ${monitor.getStatus()}`);
const unsubscribe = monitor.subscribe((online) => {
console.log(`Network status changed: ${online ? 'online' : 'offline'}`);
});
console.log('Subscribed to network status changes');
// 4. Request validation
console.log('\n--- 4. Request Validation ---');
const urlValidation = RequestValidator.validateUrl('https://example.com');
console.log(`URL valid: ${urlValidation.valid}`);
const methodValidation = RequestValidator.validateMethod('GET');
console.log(`Method valid: ${methodValidation.valid}`);
const headersValidation = RequestValidator.validateHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
});
console.log(`Headers valid: ${headersValidation.valid}`);
// 5. CORS utilities
console.log('\n--- 5. CORS Utilities ---');
const crossOrigin = CorsUtilities.isCrossOrigin('https://api.example.com/data');
console.log(`Is cross-origin: ${crossOrigin}`);
const needsPreflight = CorsUtilities.isPreflightRequired('PUT', { 'X-Custom-Header': 'value' });
console.log(`Needs preflight: ${needsPreflight}`);
// 6. Request retry
console.log('\n--- 6. Request Retry ---');
let attempts = 0;
const result = await RequestRetryHandler.retryWithBackoff(async () => {
attempts++;
console.log(`Attempt ${attempts}`);
if (attempts < 2) {
throw new Error('Temporary failure');
}
return 'Success!';
}, 3, 100);
console.log(`Retry result: ${result}`);
// 7. Connection pool
console.log('\n--- 7. Connection Pool ---');
const pool = new ConnectionPool(3);
const poolPromises = Array.from({ length: 5 }, (_, i) =>
pool.execute(async () => {
console.log(`Request ${i + 1} started (pool size: ${pool.size})`);
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Request ${i + 1} completed`);
return i;
})
);
await Promise.all(poolPromises);
// 8. Request logger
console.log('\n--- 8. Request Logger ---');
const logger = new NetworkRequestLogger();
await logger.logRequest(
async () => {
await new Promise(resolve => setTimeout(resolve, 50));
return 'data';
},
'https://api.example.com/data',
'GET'
);
const stats = logger.getStats();
console.log(`Logger stats:`, stats);
console.log('\n=== All Network Utilities Examples Completed ===');
}
// Export classes
export { UrlUtilities, QueryStringUtilities, NetworkStatusMonitor, RequestValidator, CorsUtilities, RequestRetryHandler, ConnectionPool, NetworkRequestLogger };
export { demonstrateNetworkUtilities };
💻 Requêtes HTTP typescript
🟡 intermediate
⭐⭐⭐
Envoyer des requêtes GET, POST, PUT, DELETE en utilisant Fetch API avec gestion des erreurs et analyse des réponses
⏱️ 25 min
🏷️ typescript, web, networking, http
Prerequisites:
Intermediate TypeScript, Fetch API
// Web TypeScript HTTP Requests Examples
// Using Fetch API for HTTP communication with servers
// 1. Basic HTTP Request Methods
class HttpClient {
private baseURL: string;
private defaultHeaders: Record<string, string>;
constructor(baseURL: string = '', defaultHeaders: Record<string, string> = {}) {
this.baseURL = baseURL;
this.defaultHeaders = {
'Content-Type': 'application/json',
...defaultHeaders
};
}
// GET request
async get<T>(url: string, headers?: Record<string, string>): Promise<T> {
const response = await fetch(`${this.baseURL}${url}`, {
method: 'GET',
headers: { ...this.defaultHeaders, ...headers }
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// POST request
async post<T>(url: string, data: any, headers?: Record<string, string>): Promise<T> {
const response = await fetch(`${this.baseURL}${url}`, {
method: 'POST',
headers: { ...this.defaultHeaders, ...headers },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// PUT request
async put<T>(url: string, data: any, headers?: Record<string, string>): Promise<T> {
const response = await fetch(`${this.baseURL}${url}`, {
method: 'PUT',
headers: { ...this.defaultHeaders, ...headers },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// DELETE request
async delete<T>(url: string, headers?: Record<string, string>): Promise<T> {
const response = await fetch(`${this.baseURL}${url}`, {
method: 'DELETE',
headers: { ...this.defaultHeaders, ...headers }
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// PATCH request
async patch<T>(url: string, data: any, headers?: Record<string, string>): Promise<T> {
const response = await fetch(`${this.baseURL}${url}`, {
method: 'PATCH',
headers: { ...this.defaultHeaders, ...headers },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
}
// 2. Advanced HTTP Features
class AdvancedHttpClient {
// Request with query parameters
async getWithQueryParams<T>(
url: string,
params: Record<string, string | number>
): Promise<T> {
const queryString = new URLSearchParams(
Object.entries(params).map(([k, v]) => [k, String(v)])
).toString();
const response = await fetch(`${url}?${queryString}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// Request with timeout
async fetchWithTimeout<T>(
url: string,
options: RequestInit = {},
timeout: number = 5000
): Promise<T> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} finally {
clearTimeout(timeoutId);
}
}
// Upload file with progress
async uploadFile(
url: string,
file: File,
onProgress?: (progress: number) => void
): Promise<Response> {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable && onProgress) {
const progress = Math.round((e.loaded / e.total) * 100);
onProgress(progress);
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(new Response(xhr.responseText, { status: xhr.status }));
} else {
reject(new Error(`HTTP error! status: ${xhr.status}`));
}
});
xhr.addEventListener('error', () => {
reject(new Error('Network error'));
});
xhr.open('POST', url);
xhr.send(file);
});
}
// Download file
async downloadFile(url: string, fileName: string): Promise<void> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const blob = await response.blob();
const blobUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = blobUrl;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(blobUrl);
}
// Request with retry
async fetchWithRetry<T>(
url: string,
options: RequestInit = {},
maxRetries: number = 3,
delayMs: number = 1000
): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
await new Promise(resolve => setTimeout(resolve, delayMs * attempt));
}
}
throw new Error('Max retries exceeded');
}
}
// 3. Request/Response Interceptors
class HttpClientWithInterceptors {
private requestInterceptors: Array<(config: RequestInit) => RequestInit> = [];
private responseInterceptors: Array<(response: Response) => Promise<Response>> = [];
// Add request interceptor
addRequestInterceptor(interceptor: (config: RequestInit) => RequestInit): void {
this.requestInterceptors.push(interceptor);
}
// Add response interceptor
addResponseInterceptor(interceptor: (response: Response) => Promise<Response>): void {
this.responseInterceptors.push(interceptor);
}
// Execute request with interceptors
async fetchWithInterceptors(url: string, options: RequestInit = {}): Promise<Response> {
let config = options;
// Apply request interceptors
for (const interceptor of this.requestInterceptors) {
config = interceptor(config);
}
let response = await fetch(url, config);
// Apply response interceptors
for (const interceptor of this.responseInterceptors) {
response = await interceptor(response);
}
return response;
}
}
// 4. API Client Builder
class ApiClientBuilder {
private baseURL: string = '';
private headers: Record<string, string> = {};
private interceptors: {
request: Array<(config: RequestInit) => RequestInit>;
response: Array<(response: Response) => Promise<Response>>;
} = { request: [], response: [] };
setBaseURL(url: string): this {
this.baseURL = url;
return this;
}
setHeader(key: string, value: string): this {
this.headers[key] = value;
return this;
}
setHeaders(headers: Record<string, string>): this {
this.headers = { ...this.headers, ...headers };
return this;
}
addRequestInterceptor(interceptor: (config: RequestInit) => RequestInit): this {
this.interceptors.request.push(interceptor);
return this;
}
addResponseInterceptor(interceptor: (response: Response) => Promise<Response>): this {
this.interceptors.response.push(interceptor);
return this;
}
build(): HttpClient {
const client = new HttpClient(this.baseURL, this.headers);
// Apply interceptors to client if needed
// This is a simplified version
return client;
}
}
// 5. REST API Client
class RestClient {
private client: HttpClient;
constructor(baseURL: string, authToken?: string) {
const headers: Record<string, string> = {};
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}
this.client = new HttpClient(baseURL, headers);
}
// CRUD operations
async getAll<T>(resource: string): Promise<T[]> {
return this.client.get<T[]>(`/${resource}`);
}
async getById<T>(resource: string, id: string | number): Promise<T> {
return this.client.get<T>(`/${resource}/${id}`);
}
async create<T>(resource: string, data: any): Promise<T> {
return this.client.post<T>(`/${resource}`, data);
}
async update<T>(resource: string, id: string | number, data: any): Promise<T> {
return this.client.put<T>(`/${resource}/${id}`, data);
}
async patch<T>(resource: string, id: string | number, data: any): Promise<T> {
return this.client.patch<T>(`/${resource}/${id}`, data);
}
async delete<T>(resource: string, id: string | number): Promise<T> {
return this.client.delete<T>(`/${resource}/${id}`);
}
// Query operations
async query<T>(resource: string, params: Record<string, any>): Promise<T[]> {
const advancedClient = new AdvancedHttpClient();
return advancedClient.getWithQueryParams<T[]>(`${this.client['baseURL']}/${resource}`, params);
}
}
// 6. GraphQL Client
class GraphQLClient {
private endpoint: string;
private headers: Record<string, string>;
constructor(endpoint: string, headers: Record<string, string> = {}) {
this.endpoint = endpoint;
this.headers = {
'Content-Type': 'application/json',
...headers
};
}
async query<T>(query: string, variables?: Record<string, any>): Promise<T> {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({
query,
variables
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.errors) {
throw new Error(result.errors[0].message);
}
return result.data;
}
async mutate<T>(mutation: string, variables?: Record<string, any>): Promise<T> {
return this.query<T>(mutation, variables);
}
}
// 7. Response Caching
class CachedHttpClient {
private cache = new Map<string, { data: any; timestamp: number }>();
private cacheTimeout: number;
constructor(cacheTimeout: number = 60000) {
this.cacheTimeout = cacheTimeout;
}
async get<T>(url: string, useCache: boolean = true): Promise<T> {
if (useCache && this.cache.has(url)) {
const cached = this.cache.get(url)!;
const age = Date.now() - cached.timestamp;
if (age < this.cacheTimeout) {
return cached.data as T;
}
}
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
this.cache.set(url, { data, timestamp: Date.now() });
return data as T;
}
clearCache(): void {
this.cache.clear();
}
clearCacheEntry(url: string): void {
this.cache.delete(url);
}
}
// 8. Batch Requests
class BatchRequestClient {
// Execute multiple requests concurrently
async fetchAll<T>(requests: Array<{ url: string; options?: RequestInit }>): Promise<T[]> {
const promises = requests.map(req => fetch(req.url, req.options));
const responses = await Promise.all(promises);
const results: T[] = [];
for (const response of responses) {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
results.push(await response.json());
}
return results;
}
// Execute requests in batches
async fetchInBatches<T>(
requests: Array<{ url: string; options?: RequestInit }>,
batchSize: number = 5
): Promise<T[]> {
const results: T[] = [];
for (let i = 0; i < requests.length; i += batchSize) {
const batch = requests.slice(i, i + batchSize);
const batchResults = await this.fetchAll<T>(batch);
results.push(...batchResults);
}
return results;
}
}
// Usage Examples
async function demonstrateHttpRequests() {
console.log('=== Web TypeScript HTTP Requests Examples ===\n');
// 1. Basic HTTP methods
console.log('--- 1. Basic HTTP Methods ---');
const client = new HttpClient('https://jsonplaceholder.typicode.com');
try {
const posts = await client.get('/posts');
console.log(`GET /posts: Retrieved ${(posts as any).length} posts`);
const newPost = await client.post('/posts', {
title: 'Test Post',
body: 'This is a test post',
userId: 1
});
console.log(`POST /posts: Created post with ID ${(newPost as any).id}`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
// 2. Query parameters
console.log('\n--- 2. Query Parameters ---');
const advancedClient = new AdvancedHttpClient();
try {
const filteredPosts = await advancedClient.getWithQueryParams(
'https://jsonplaceholder.typicode.com/posts',
{ userId: 1, _limit: 5 }
);
console.log(`Filtered posts: ${(filteredPosts as any).length} results`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
// 3. Request with timeout
console.log('\n--- 3. Request with Timeout ---');
try {
const result = await advancedClient.fetchWithTimeout(
'https://jsonplaceholder.typicode.com/posts/1',
{},
3000
);
console.log(`Request completed: ${JSON.stringify(result).substring(0, 100)}...`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
// 4. REST API client
console.log('\n--- 4. REST API Client ---');
const restClient = new RestClient('https://jsonplaceholder.typicode.com');
try {
const todos = await restClient.getAll('todos');
console.log(`GET /todos: ${todos.length} items`);
const todo = await restClient.getById('todos', 1);
console.log(`GET /todos/1: ${todo.title}`);
const newTodo = await restClient.create('todos', {
title: 'New Todo',
completed: false
});
console.log(`POST /todos: Created ID ${newTodo.id}`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
// 5. GraphQL query
console.log('\n--- 5. GraphQL Query ---');
const graphqlClient = new GraphQLClient('https://api.github.com/graphql', {
Authorization: 'Bearer YOUR_TOKEN'
});
const query = `
query {
viewer {
login
name
}
}
`;
console.log('GraphQL query prepared (requires auth token)');
// 6. Cached requests
console.log('\n--- 6. Cached Requests ---');
const cachedClient = new CachedHttpClient(60000);
try {
const start1 = Date.now();
await cachedClient.get('https://jsonplaceholder.typicode.com/users');
const time1 = Date.now() - start1;
const start2 = Date.now();
await cachedClient.get('https://jsonplaceholder.typicode.com/users');
const time2 = Date.now() - start2;
console.log(`First request: ${time1}ms`);
console.log(`Cached request: ${time2}ms`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
// 7. Batch requests
console.log('\n--- 7. Batch Requests ---');
const batchClient = new BatchRequestClient();
try {
const batchResults = await batchClient.fetchAll([
{ url: 'https://jsonplaceholder.typicode.com/posts/1' },
{ url: 'https://jsonplaceholder.typicode.com/posts/2' },
{ url: 'https://jsonplaceholder.typicode.com/posts/3' }
]);
console.log(`Batch request completed: ${batchResults.length} results`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
console.log('\n=== All HTTP Requests Examples Completed ===');
}
// Export classes
export { HttpClient, AdvancedHttpClient, HttpClientWithInterceptors, ApiClientBuilder, RestClient, GraphQLClient, CachedHttpClient, BatchRequestClient };
export { demonstrateHttpRequests };
💻 Communication WebSocket typescript
🟡 intermediate
⭐⭐⭐
Établir une communication bidirectionnelle en temps réel en utilisant WebSocket API avec reconnexion et gestion des messages
⏱️ 30 min
🏷️ typescript, web, networking, websocket
Prerequisites:
Intermediate TypeScript, WebSocket API
// Web TypeScript WebSocket Communication Examples
// Real-time bidirectional communication using WebSocket API
// 1. Basic WebSocket Connection
class WebSocketClient {
private ws: WebSocket | null = null;
private url: string;
private reconnectAttempts: number = 0;
private maxReconnectAttempts: number = 5;
private reconnectDelay: number = 1000;
constructor(url: string) {
this.url = url;
}
// Connect to WebSocket server
connect(): Promise<void> {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket connected');
this.reconnectAttempts = 0;
resolve();
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onclose = () => {
console.log('WebSocket disconnected');
this.attemptReconnect();
};
});
}
// Send message
send(data: string | object): void {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
throw new Error('WebSocket is not connected');
}
const message = typeof data === 'string' ? data : JSON.stringify(data);
this.ws.send(message);
}
// Receive message
onMessage(callback: (data: any) => void): void {
if (!this.ws) {
throw new Error('WebSocket is not initialized');
}
this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
callback(data);
} catch {
callback(event.data);
}
};
}
// Close connection
close(): void {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
// Attempt to reconnect
private attemptReconnect(): void {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = this.reconnectDelay * this.reconnectAttempts;
console.log(`Reconnecting in ${delay}ms... (attempt ${this.reconnectAttempts})`);
setTimeout(() => {
this.connect();
}, delay);
} else {
console.error('Max reconnection attempts reached');
}
}
// Get connection state
get readyState(): number {
return this.ws?.readyState ?? WebSocket.CLOSED;
}
}
// 2. Advanced WebSocket with Message Queuing
class AdvancedWebSocketClient {
private ws: WebSocket | null = null;
private messageQueue: Array<string | object> = [];
private isManuallyClosed: boolean = false;
private messageHandlers: Map<string, Array<(data: any) => void>> = new Map();
private reconnectTimeout: number = 5000;
private pingInterval: NodeJS.Timeout | null = null;
constructor(private url: string) {}
// Connect with automatic reconnection
async connect(): Promise<void> {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket connected');
this.startPing();
this.flushMessageQueue();
resolve();
};
this.ws.onmessage = (event) => {
this.handleMessage(event);
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onclose = () => {
console.log('WebSocket disconnected');
this.stopPing();
if (!this.isManuallyClosed) {
setTimeout(() => this.connect(), this.reconnectTimeout);
}
};
});
}
// Send message immediately or queue it
send(data: string | object, type?: string): void {
const message = type ? { type, data } : data;
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
} else {
this.messageQueue.push(message);
console.log('Message queued');
}
}
// Flush queued messages
private flushMessageQueue(): void {
while (this.messageQueue.length > 0 && this.ws?.readyState === WebSocket.OPEN) {
const message = this.messageQueue.shift();
this.ws.send(JSON.stringify(message));
}
}
// Handle incoming message
private handleMessage(event: MessageEvent): void {
try {
const message = JSON.parse(event.data);
if (message.type && this.messageHandlers.has(message.type)) {
const handlers = this.messageHandlers.get(message.type)!;
handlers.forEach(handler => handler(message.data));
}
} catch (error) {
console.error('Failed to parse message:', error);
}
}
// Register message handler
on(type: string, callback: (data: any) => void): void {
if (!this.messageHandlers.has(type)) {
this.messageHandlers.set(type, []);
}
this.messageHandlers.get(type)!.push(callback);
}
// Remove message handler
off(type: string, callback: (data: any) => void): void {
const handlers = this.messageHandlers.get(type);
if (handlers) {
const index = handlers.indexOf(callback);
if (index > -1) {
handlers.splice(index, 1);
}
}
}
// Start ping to keep connection alive
private startPing(): void {
this.pingInterval = setInterval(() => {
this.send({ type: 'ping', timestamp: Date.now() });
}, 30000);
}
// Stop ping
private stopPing(): void {
if (this.pingInterval) {
clearInterval(this.pingInterval);
this.pingInterval = null;
}
}
// Close connection
close(): void {
this.isManuallyClosed = true;
this.stopPing();
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
}
// 3. WebSocket Room/Channel Management
class WebSocketRoomClient {
private client: AdvancedWebSocketClient;
private currentRooms: Set<string> = new Set();
constructor(url: string) {
this.client = new AdvancedWebSocketClient(url);
}
// Connect to server
async connect(): Promise<void> {
await this.client.connect();
}
// Join room
joinRoom(roomName: string): void {
if (!this.currentRooms.has(roomName)) {
this.client.send({ type: 'join', room: roomName });
this.currentRooms.add(roomName);
console.log(`Joined room: ${roomName}`);
}
}
// Leave room
leaveRoom(roomName: string): void {
if (this.currentRooms.has(roomName)) {
this.client.send({ type: 'leave', room: roomName });
this.currentRooms.delete(roomName);
console.log(`Left room: ${roomName}`);
}
}
// Send message to room
sendToRoom(roomName: string, message: any): void {
this.client.send({
type: 'room_message',
room: roomName,
data: message
});
}
// Listen to room messages
onRoomMessage(roomName: string, callback: (message: any) => void): void {
this.client.on('room_message', (data) => {
if (data.room === roomName) {
callback(data.message);
}
});
}
// Leave all rooms
leaveAllRooms(): void {
this.currentRooms.forEach(room => this.leaveRoom(room));
}
// Close connection
close(): void {
this.leaveAllRooms();
this.client.close();
}
}
// 4. WebSocket with Authentication
class AuthenticatedWebSocketClient {
private ws: WebSocket | null = null;
private authToken: string;
private reconnectOnAuthFailure: boolean = true;
constructor(
private url: string,
authToken: string
) {
this.authToken = authToken;
}
// Connect with authentication
async connect(): Promise<void> {
const wsUrl = `${this.url}?token=${this.authToken}`;
return new Promise((resolve, reject) => {
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log('Authenticated WebSocket connected');
resolve();
};
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
// Handle authentication failure
if (message.type === 'auth_error') {
console.error('Authentication failed:', message.error);
if (this.reconnectOnAuthFailure) {
// Could trigger token refresh here
}
reject(new Error(message.error));
}
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onclose = (event) => {
console.log(`WebSocket closed: ${event.code}`);
};
});
}
// Send authenticated message
send(data: any): void {
if (this.ws?.readyState === WebSocket.OPEN) {
const message = {
...data,
token: this.authToken
};
this.ws.send(JSON.stringify(message));
}
}
// Update authentication token
updateToken(newToken: string): void {
this.authToken = newToken;
}
// Close connection
close(): void {
this.ws?.close();
}
}
// 5. Binary Data Handling
class BinaryWebSocketClient {
private ws: WebSocket | null = null;
constructor(private url: string) {}
// Connect
async connect(binaryType: BinaryType = 'blob'): Promise<void> {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.url);
this.ws.binaryType = binaryType;
this.ws.onopen = () => resolve();
this.ws.onerror = reject;
});
}
// Send binary data
sendBinary(data: ArrayBuffer | Blob): void {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
}
// Receive binary data
onBinaryData(callback: (data: ArrayBuffer | Blob) => void): void {
if (this.ws) {
this.ws.onmessage = (event) => {
callback(event.data);
};
}
}
// Close connection
close(): void {
this.ws?.close();
}
}
// 6. WebSocket RPC (Remote Procedure Call)
class WebSocketRPCClient {
private requestCallbacks: Map<number, (response: any) => void> = new Map();
private requestId: number = 0;
private client: AdvancedWebSocketClient;
constructor(url: string) {
this.client = new AdvancedWebSocketClient(url);
}
// Connect
async connect(): Promise<void> {
await this.client.connect();
// Listen for RPC responses
this.client.on('rpc_response', (data) => {
const { id, result, error } = data;
const callback = this.requestCallbacks.get(id);
if (callback) {
callback({ result, error });
this.requestCallbacks.delete(id);
}
});
}
// Call remote method
async call(method: string, params?: any): Promise<any> {
const id = ++this.requestId;
return new Promise((resolve, reject) => {
this.requestCallbacks.set(id, ({ result, error }) => {
if (error) {
reject(new Error(error));
} else {
resolve(result);
}
});
this.client.send({
type: 'rpc_request',
id,
method,
params
});
});
}
// Register remote method handler
on(method: string, handler: (params: any) => any): void {
this.client.on('rpc_request', async (data) => {
if (data.method === method) {
try {
const result = await handler(data.params);
this.client.send({
type: 'rpc_response',
id: data.id,
result
});
} catch (error) {
this.client.send({
type: 'rpc_response',
id: data.id,
error: (error as Error).message
});
}
}
});
}
// Close connection
close(): void {
this.client.close();
}
}
// 7. WebSocket Statistics and Monitoring
class MonitoredWebSocketClient {
private client: WebSocketClient;
private stats = {
messagesSent: 0,
messagesReceived: 0,
bytesSent: 0,
bytesReceived: 0,
connectionTime: 0,
reconnectionCount: 0
};
constructor(url: string) {
this.client = new WebSocketClient(url);
}
// Connect with monitoring
async connect(): Promise<void> {
this.stats.connectionTime = Date.now();
await this.client.connect();
// Wrap message handler to monitor
this.client.onMessage((data) => {
this.stats.messagesReceived++;
this.stats.bytesReceived += JSON.stringify(data).length;
});
}
// Send with monitoring
send(data: any): void {
const message = JSON.stringify(data);
this.stats.messagesSent++;
this.stats.bytesSent += message.length;
this.client.send(data);
}
// Get statistics
getStats(): typeof this.stats {
return {
...this.stats,
uptime: Date.now() - this.stats.connectionTime
};
}
// Print statistics
printStats(): void {
const stats = this.getStats();
console.log('\n=== WebSocket Statistics ===');
console.log(`Messages Sent: ${stats.messagesSent}`);
console.log(`Messages Received: ${stats.messagesReceived}`);
console.log(`Bytes Sent: ${stats.bytesSent}`);
console.log(`Bytes Received: ${stats.bytesReceived}`);
console.log(`Uptime: ${stats.uptime}ms`);
}
// Close connection
close(): void {
this.client.close();
}
}
// Usage Examples
async function demonstrateWebSocket() {
console.log('=== Web TypeScript WebSocket Examples ===\n');
// Note: These examples require a WebSocket server to connect to
// Replace 'ws://localhost:8080' with your WebSocket server URL
// 1. Basic WebSocket
console.log('--- 1. Basic WebSocket Connection ---');
const basicClient = new WebSocketClient('ws://localhost:8080');
try {
// Uncomment to test with actual server
// await basicClient.connect();
// basicClient.send({ type: 'greeting', message: 'Hello Server!' });
// basicClient.onMessage((data) => console.log('Received:', data));
console.log('Basic WebSocket client created (requires server)');
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
// 2. Advanced WebSocket with message handlers
console.log('\n--- 2. Advanced WebSocket ---');
const advancedClient = new AdvancedWebSocketClient('ws://localhost:8080');
// Register message handlers
advancedClient.on('chat', (data) => {
console.log('Chat message:', data);
});
advancedClient.on('notification', (data) => {
console.log('Notification:', data);
});
console.log('Advanced WebSocket client with handlers created');
// 3. Room management
console.log('\n--- 3. Room Management ---');
const roomClient = new WebSocketRoomClient('ws://localhost:8080');
// Uncomment to test with actual server
// await roomClient.connect();
// roomClient.joinRoom('general');
// roomClient.sendToRoom('general', { text: 'Hello everyone!' });
// roomClient.onRoomMessage('general', (msg) => console.log('Room message:', msg));
console.log('Room client created');
// 4. Authenticated WebSocket
console.log('\n--- 4. Authenticated WebSocket ---');
const authClient = new AuthenticatedWebSocketClient(
'ws://localhost:8080',
'your-auth-token'
);
console.log('Authenticated WebSocket client created');
// 5. RPC client
console.log('\n--- 5. WebSocket RPC ---');
const rpcClient = new WebSocketRPCClient('ws://localhost:8080');
// Uncomment to test with actual server
// await rpcClient.connect();
// const result = await rpcClient.call('add', { a: 5, b: 3 });
// console.log('RPC result:', result);
console.log('RPC client created');
// 6. Monitoring
console.log('\n--- 6. WebSocket Monitoring ---');
const monitoredClient = new MonitoredWebSocketClient('ws://localhost:8080');
console.log('Monitored WebSocket client created');
console.log('\n=== All WebSocket Examples Completed ===');
console.log('Note: These examples require a WebSocket server to connect to');
}
// Export classes
export { WebSocketClient, AdvancedWebSocketClient, WebSocketRoomClient, AuthenticatedWebSocketClient, BinaryWebSocketClient, WebSocketRPCClient, MonitoredWebSocketClient };
export { demonstrateWebSocket };