or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

canvas.mdcore-framework.mddevice.mddom-query.mdindex.mdlocation.mdmedia.mdnavigation.mdnetwork.mdstorage.mdsystem-info.mdui-interactions.md

network.mddocs/

0

# Network APIs

1

2

Comprehensive networking capabilities including HTTP requests with interceptor support, designed for web environments using modern fetch API with Mini Program compatibility.

3

4

## Capabilities

5

6

### HTTP Request API

7

8

Full-featured HTTP client supporting all standard methods, headers, data formats, and advanced options.

9

10

```typescript { .api }

11

/**

12

* Make HTTP request with full configuration support

13

* @param options - Request configuration options

14

* @returns Promise resolving to response with data, status, and headers

15

*/

16

function request(options: RequestOption): Promise<RequestResult>;

17

18

interface RequestOption {

19

/** Target URL for the request (required) */

20

url: string;

21

/** Request body data (JSON serialized for non-GET requests) */

22

data?: any;

23

/** HTTP headers object */

24

header?: Record<string, string>;

25

/** HTTP method (default: 'GET') */

26

method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';

27

/** Expected response data type (default: 'json') */

28

dataType?: 'json' | 'text' | 'base64';

29

/** Response type for binary data (default: 'text') */

30

responseType?: 'text' | 'json' | 'arraybuffer';

31

/** Request timeout in milliseconds (default: 60000) */

32

timeout?: number;

33

/** Enable HTTP/2 support (browser dependent) */

34

enableHttp2?: boolean;

35

/** Enable QUIC support (browser dependent) */

36

enableQuic?: boolean;

37

/** Enable response caching (browser dependent) */

38

enableCache?: boolean;

39

/** Enable credentials for cross-origin requests */

40

credentials?: boolean;

41

/** Success callback function */

42

success?: (result: RequestResult) => void;

43

/** Failure callback function */

44

fail?: (error: any) => void;

45

/** Completion callback function */

46

complete?: (result: RequestResult | any) => void;

47

}

48

49

interface RequestResult {

50

/** Response data (parsed based on dataType) */

51

data: any;

52

/** HTTP status code */

53

statusCode: number;

54

/** Response headers object */

55

header: Record<string, string>;

56

/** Response cookies (if any) */

57

cookies?: string[];

58

/** Error message (if request failed) */

59

errMsg?: string;

60

}

61

```

62

63

**Usage Examples:**

64

65

```typescript

66

import { request } from "@tarojs/taro-h5";

67

68

// Basic GET request

69

const getUserData = async (userId: string) => {

70

try {

71

const response = await request({

72

url: `https://api.example.com/users/${userId}`,

73

method: 'GET',

74

header: {

75

'Authorization': 'Bearer token123',

76

'Content-Type': 'application/json'

77

}

78

});

79

80

console.log('User data:', response.data);

81

console.log('Status:', response.statusCode);

82

return response.data;

83

} catch (error) {

84

console.error('Failed to fetch user:', error);

85

throw error;

86

}

87

};

88

89

// POST request with data

90

const createUser = async (userData: any) => {

91

const response = await request({

92

url: 'https://api.example.com/users',

93

method: 'POST',

94

data: userData,

95

header: {

96

'Content-Type': 'application/json',

97

'Authorization': 'Bearer token123'

98

},

99

timeout: 10000

100

});

101

102

return response.data;

103

};

104

105

// PUT request for updates

106

const updateUserProfile = async (userId: string, profileData: any) => {

107

const response = await request({

108

url: `https://api.example.com/users/${userId}`,

109

method: 'PUT',

110

data: profileData,

111

header: {

112

'Content-Type': 'application/json',

113

'X-Request-ID': Date.now().toString()

114

}

115

});

116

117

return response.statusCode === 200;

118

};

119

120

// DELETE request

121

const deleteUser = async (userId: string) => {

122

await request({

123

url: `https://api.example.com/users/${userId}`,

124

method: 'DELETE',

125

header: {

126

'Authorization': 'Bearer token123'

127

}

128

});

129

};

130

```

131

132

### Request Interceptors

133

134

Powerful interceptor system for modifying requests and responses globally across the application.

135

136

```typescript { .api }

137

/**

138

* Add request interceptor to modify requests before they are sent

139

* @param interceptor - Interceptor function or object

140

*/

141

function addInterceptor(interceptor: Interceptor): void;

142

143

/**

144

* Remove all registered interceptors

145

*/

146

function cleanInterceptors(): void;

147

148

interface Interceptor {

149

/** Request interceptor function */

150

request?: (config: RequestOption) => RequestOption | Promise<RequestOption>;

151

/** Response interceptor function */

152

response?: (response: RequestResult) => RequestResult | Promise<RequestResult>;

153

/** Error interceptor function */

154

responseError?: (error: any) => any | Promise<any>;

155

}

156

157

// Alternative function-based interceptor

158

type InterceptorFunction = (config: RequestOption) => RequestOption | Promise<RequestOption>;

159

```

160

161

### File Download API

162

163

Full-featured file download functionality with progress tracking and binary data support.

164

165

```typescript { .api }

166

/**

167

* Download file from remote server to temporary local path

168

* @param options - Download configuration options

169

* @returns Promise resolving to download task with progress tracking

170

*/

171

function downloadFile(options: DownloadFileOption): Promise<DownloadFileResult> & DownloadTask;

172

173

interface DownloadFileOption {

174

/** Target URL for file download (required) */

175

url: string;

176

/** HTTP headers object */

177

header?: Record<string, string>;

178

/** Include credentials for cross-origin requests */

179

withCredentials?: boolean;

180

/** Request timeout in milliseconds (default: 60000) */

181

timeout?: number;

182

/** Success callback function */

183

success?: (result: DownloadFileResult) => void;

184

/** Failure callback function */

185

fail?: (error: any) => void;

186

/** Completion callback function */

187

complete?: (result: DownloadFileResult | any) => void;

188

}

189

190

interface DownloadFileResult {

191

/** Temporary file path (blob URL) */

192

tempFilePath: string;

193

/** HTTP status code */

194

statusCode: number;

195

/** Error message (if download failed) */

196

errMsg?: string;

197

}

198

199

interface DownloadTask {

200

/** Abort the download operation */

201

abort(): void;

202

/** Monitor HTTP Response Header events */

203

onHeadersReceived(callback: (res: { header: string }) => void): void;

204

/** Remove HTTP Response Header event listener */

205

offHeadersReceived(callback: (res: { header: string }) => void): void;

206

/** Monitor download progress events */

207

onProgressUpdate(callback: (res: DownloadProgressResult) => void): void;

208

/** Remove download progress event listener */

209

offProgressUpdate(callback: (res: DownloadProgressResult) => void): void;

210

}

211

212

interface DownloadProgressResult {

213

/** Download progress percentage (0-100) */

214

progress: number;

215

/** Total bytes written so far */

216

totalBytesWritten: number;

217

/** Expected total bytes to write */

218

totalBytesExpectedToWrite: number;

219

}

220

```

221

222

**Usage Examples:**

223

224

```typescript

225

import { downloadFile } from "@tarojs/taro-h5";

226

227

// Basic file download

228

const downloadImage = async () => {

229

try {

230

const result = await downloadFile({

231

url: 'https://example.com/image.jpg',

232

header: {

233

'Authorization': 'Bearer token123'

234

}

235

});

236

237

console.log('Downloaded to:', result.tempFilePath);

238

console.log('Status:', result.statusCode);

239

240

// Use the temporary file path (blob URL)

241

const img = document.createElement('img');

242

img.src = result.tempFilePath;

243

document.body.appendChild(img);

244

245

} catch (error) {

246

console.error('Download failed:', error);

247

}

248

};

249

250

// Download with progress tracking

251

const downloadWithProgress = () => {

252

const task = downloadFile({

253

url: 'https://example.com/large-file.zip',

254

success: (res) => {

255

console.log('Download completed:', res.tempFilePath);

256

},

257

fail: (error) => {

258

console.error('Download failed:', error);

259

}

260

});

261

262

// Track download progress

263

task.onProgressUpdate((res) => {

264

console.log(`Progress: ${res.progress}%`);

265

console.log(`Downloaded: ${res.totalBytesWritten} / ${res.totalBytesExpectedToWrite} bytes`);

266

267

// Update UI progress bar

268

updateProgressBar(res.progress);

269

});

270

271

// Handle headers received

272

task.onHeadersReceived((res) => {

273

console.log('Headers received:', res.header);

274

});

275

276

// Cancel download if needed

277

setTimeout(() => {

278

task.abort();

279

console.log('Download cancelled');

280

}, 10000); // Cancel after 10 seconds

281

};

282

```

283

284

### File Upload API

285

286

Multipart form data upload functionality with progress tracking and metadata support.

287

288

```typescript { .api }

289

/**

290

* Upload local file to remote server using multipart/form-data

291

* @param options - Upload configuration options

292

* @returns Promise resolving to upload task with progress tracking

293

*/

294

function uploadFile(options: UploadFileOption): Promise<UploadFileResult> & UploadTask;

295

296

interface UploadFileOption {

297

/** Target URL for file upload (required) */

298

url: string;

299

/** File path to upload (blob URL or File object) */

300

filePath: string;

301

/** Form field name for the file (required) */

302

name: string;

303

/** HTTP headers object */

304

header?: Record<string, string>;

305

/** Additional form data fields */

306

formData?: Record<string, string>;

307

/** Request timeout in milliseconds (default: 60000) */

308

timeout?: number;

309

/** Custom filename for the uploaded file */

310

fileName?: string;

311

/** Include credentials for cross-origin requests */

312

withCredentials?: boolean;

313

/** Success callback function */

314

success?: (result: UploadFileResult) => void;

315

/** Failure callback function */

316

fail?: (error: any) => void;

317

/** Completion callback function */

318

complete?: (result: UploadFileResult | any) => void;

319

}

320

321

interface UploadFileResult {

322

/** Server response data */

323

data: string;

324

/** HTTP status code */

325

statusCode: number;

326

/** Error message (if upload failed) */

327

errMsg?: string;

328

}

329

330

interface UploadTask {

331

/** Abort the upload operation */

332

abort(): void;

333

/** Monitor HTTP Response Header events */

334

onHeadersReceived(callback: (res: { header: string }) => void): void;

335

/** Remove HTTP Response Header event listener */

336

offHeadersReceived(callback: (res: { header: string }) => void): void;

337

/** Monitor upload progress events */

338

onProgressUpdate(callback: (res: UploadProgressResult) => void): void;

339

/** Remove upload progress event listener */

340

offProgressUpdate(callback: (res: UploadProgressResult) => void): void;

341

}

342

343

interface UploadProgressResult {

344

/** Upload progress percentage (0-100) */

345

progress: number;

346

/** Total bytes sent so far */

347

totalBytesSent: number;

348

/** Expected total bytes to send */

349

totalBytesExpectedToSend: number;

350

}

351

```

352

353

**Usage Examples:**

354

355

```typescript

356

import { uploadFile } from "@tarojs/taro-h5";

357

358

// Basic file upload

359

const uploadImage = async (fileBlob: Blob) => {

360

try {

361

// Create blob URL from file

362

const filePath = URL.createObjectURL(fileBlob);

363

364

const result = await uploadFile({

365

url: 'https://api.example.com/upload',

366

filePath: filePath,

367

name: 'image',

368

fileName: 'photo.jpg',

369

header: {

370

'Authorization': 'Bearer token123'

371

},

372

formData: {

373

'userId': '12345',

374

'category': 'profile'

375

}

376

});

377

378

console.log('Upload completed');

379

console.log('Server response:', result.data);

380

console.log('Status:', result.statusCode);

381

382

// Clean up blob URL

383

URL.revokeObjectURL(filePath);

384

385

} catch (error) {

386

console.error('Upload failed:', error);

387

}

388

};

389

390

// Upload with progress tracking

391

const uploadWithProgress = (fileInput: HTMLInputElement) => {

392

const file = fileInput.files?.[0];

393

if (!file) return;

394

395

const filePath = URL.createObjectURL(file);

396

397

const task = uploadFile({

398

url: 'https://api.example.com/upload',

399

filePath: filePath,

400

name: 'file',

401

fileName: file.name,

402

formData: {

403

'timestamp': Date.now().toString(),

404

'fileSize': file.size.toString()

405

},

406

success: (res) => {

407

console.log('Upload successful:', JSON.parse(res.data));

408

URL.revokeObjectURL(filePath);

409

},

410

fail: (error) => {

411

console.error('Upload failed:', error);

412

URL.revokeObjectURL(filePath);

413

}

414

});

415

416

// Track upload progress

417

task.onProgressUpdate((res) => {

418

console.log(`Upload progress: ${res.progress}%`);

419

console.log(`Uploaded: ${res.totalBytesSent} / ${res.totalBytesExpectedToSend} bytes`);

420

421

// Update UI progress

422

const progressPercent = res.progress;

423

updateUploadProgress(progressPercent);

424

});

425

426

// Handle response headers

427

task.onHeadersReceived((res) => {

428

console.log('Response headers received:', res.header);

429

});

430

431

// Cancel upload if needed

432

const cancelButton = document.getElementById('cancel-upload');

433

cancelButton?.addEventListener('click', () => {

434

task.abort();

435

console.log('Upload cancelled');

436

URL.revokeObjectURL(filePath);

437

});

438

};

439

440

// Multiple file upload

441

const uploadMultipleFiles = async (files: FileList) => {

442

const uploadPromises = Array.from(files).map(async (file) => {

443

const filePath = URL.createObjectURL(file);

444

445

try {

446

const result = await uploadFile({

447

url: 'https://api.example.com/upload',

448

filePath: filePath,

449

name: 'files',

450

fileName: file.name

451

});

452

453

URL.revokeObjectURL(filePath);

454

return { success: true, fileName: file.name, result };

455

456

} catch (error) {

457

URL.revokeObjectURL(filePath);

458

return { success: false, fileName: file.name, error };

459

}

460

});

461

462

const results = await Promise.all(uploadPromises);

463

464

results.forEach(result => {

465

if (result.success) {

466

console.log(`✓ ${result.fileName} uploaded successfully`);

467

} else {

468

console.error(`✗ ${result.fileName} failed:`, result.error);

469

}

470

});

471

};

472

```

473

474

### WebSocket APIs

475

476

Real-time bidirectional communication support using WebSocket protocol with task-based management.

477

478

```typescript { .api }

479

/**

480

* Establish WebSocket connection to remote server

481

* @param options - WebSocket connection options

482

* @returns Promise resolving to SocketTask for connection management

483

*/

484

function connectSocket(options: ConnectSocketOption): Promise<SocketTask>;

485

486

interface ConnectSocketOption {

487

/** WebSocket server URL (must use ws:// or wss://) */

488

url: string;

489

/** WebSocket sub-protocols array */

490

protocols?: string[];

491

/** Success callback function */

492

success?: (res: { socketTaskId?: number }) => void;

493

/** Failure callback function */

494

fail?: (error: any) => void;

495

/** Completion callback function */

496

complete?: (res: any) => void;

497

}

498

499

interface SocketTask {

500

/** Send data through WebSocket connection */

501

send(options: SocketSendOption): Promise<void>;

502

/** Close WebSocket connection */

503

close(options?: SocketCloseOption): Promise<void>;

504

/** Listen for connection open event */

505

onOpen(callback: (res: any) => void): void;

506

/** Remove connection open event listener */

507

offOpen(callback: (res: any) => void): void;

508

/** Listen for message received event */

509

onMessage(callback: (res: SocketMessageResult) => void): void;

510

/** Remove message received event listener */

511

offMessage(callback: (res: SocketMessageResult) => void): void;

512

/** Listen for connection error event */

513

onError(callback: (res: any) => void): void;

514

/** Remove connection error event listener */

515

offError(callback: (res: any) => void): void;

516

/** Listen for connection close event */

517

onClose(callback: (res: SocketCloseResult) => void): void;

518

/** Remove connection close event listener */

519

offClose(callback: (res: SocketCloseResult) => void): void;

520

}

521

522

interface SocketSendOption {

523

/** Data to send (string or ArrayBuffer) */

524

data: string | ArrayBuffer;

525

/** Success callback function */

526

success?: () => void;

527

/** Failure callback function */

528

fail?: (error: any) => void;

529

/** Completion callback function */

530

complete?: () => void;

531

}

532

533

interface SocketCloseOption {

534

/** Close code (default: 1000) */

535

code?: number;

536

/** Close reason */

537

reason?: string;

538

/** Success callback function */

539

success?: () => void;

540

/** Failure callback function */

541

fail?: (error: any) => void;

542

/** Completion callback function */

543

complete?: () => void;

544

}

545

546

interface SocketMessageResult {

547

/** Received message data */

548

data: string | ArrayBuffer;

549

}

550

551

interface SocketCloseResult {

552

/** Close code */

553

code: number;

554

/** Close reason */

555

reason: string;

556

/** Whether close was initiated by client */

557

wasClean: boolean;

558

}

559

```

560

561

**Usage Examples:**

562

563

```typescript

564

import { connectSocket } from "@tarojs/taro-h5";

565

566

// Basic WebSocket connection

567

const connectToWebSocket = async () => {

568

try {

569

const socketTask = await connectSocket({

570

url: 'wss://api.example.com/websocket',

571

protocols: ['chat', 'notifications']

572

});

573

574

// Handle connection opened

575

socketTask.onOpen((res) => {

576

console.log('WebSocket connected');

577

578

// Send initial message

579

socketTask.send({

580

data: JSON.stringify({

581

type: 'join',

582

userId: '12345'

583

})

584

});

585

});

586

587

// Handle incoming messages

588

socketTask.onMessage((res) => {

589

const message = JSON.parse(res.data as string);

590

console.log('Received message:', message);

591

592

// Process different message types

593

switch (message.type) {

594

case 'chat':

595

displayChatMessage(message.content);

596

break;

597

case 'notification':

598

showNotification(message.title, message.body);

599

break;

600

default:

601

console.log('Unknown message type:', message.type);

602

}

603

});

604

605

// Handle connection errors

606

socketTask.onError((error) => {

607

console.error('WebSocket error:', error);

608

});

609

610

// Handle connection closed

611

socketTask.onClose((res) => {

612

console.log('WebSocket closed:', res.code, res.reason);

613

614

// Attempt reconnection if not intentionally closed

615

if (res.code !== 1000) {

616

console.log('Attempting to reconnect...');

617

setTimeout(connectToWebSocket, 3000);

618

}

619

});

620

621

return socketTask;

622

623

} catch (error) {

624

console.error('Failed to connect WebSocket:', error);

625

}

626

};

627

628

// Chat application example

629

class WebSocketChat {

630

private socketTask: SocketTask | null = null;

631

private reconnectAttempts = 0;

632

private maxReconnectAttempts = 5;

633

634

async connect(userId: string) {

635

try {

636

this.socketTask = await connectSocket({

637

url: `wss://chat.example.com/ws?userId=${userId}`,

638

success: () => {

639

console.log('Chat connection initiated');

640

this.reconnectAttempts = 0;

641

},

642

fail: (error) => {

643

console.error('Chat connection failed:', error);

644

this.handleReconnect();

645

}

646

});

647

648

this.setupEventHandlers();

649

650

} catch (error) {

651

console.error('Failed to establish chat connection:', error);

652

this.handleReconnect();

653

}

654

}

655

656

private setupEventHandlers() {

657

if (!this.socketTask) return;

658

659

this.socketTask.onOpen(() => {

660

console.log('Chat connection established');

661

this.sendMessage({

662

type: 'user_online',

663

timestamp: Date.now()

664

});

665

});

666

667

this.socketTask.onMessage((res) => {

668

const message = JSON.parse(res.data as string);

669

this.handleIncomingMessage(message);

670

});

671

672

this.socketTask.onError((error) => {

673

console.error('Chat connection error:', error);

674

});

675

676

this.socketTask.onClose((res) => {

677

console.log('Chat connection closed');

678

if (res.code !== 1000) {

679

this.handleReconnect();

680

}

681

});

682

}

683

684

sendChatMessage(text: string) {

685

this.sendMessage({

686

type: 'chat',

687

text: text,

688

timestamp: Date.now()

689

});

690

}

691

692

sendTypingIndicator(isTyping: boolean) {

693

this.sendMessage({

694

type: 'typing',

695

isTyping: isTyping

696

});

697

}

698

699

private sendMessage(message: any) {

700

if (!this.socketTask) {

701

console.error('No active WebSocket connection');

702

return;

703

}

704

705

this.socketTask.send({

706

data: JSON.stringify(message),

707

success: () => {

708

console.log('Message sent successfully');

709

},

710

fail: (error) => {

711

console.error('Failed to send message:', error);

712

}

713

});

714

}

715

716

private handleIncomingMessage(message: any) {

717

switch (message.type) {

718

case 'chat':

719

this.displayChatMessage(message);

720

break;

721

case 'user_joined':

722

this.showUserJoined(message.userId);

723

break;

724

case 'user_left':

725

this.showUserLeft(message.userId);

726

break;

727

case 'typing':

728

this.showTypingIndicator(message.userId, message.isTyping);

729

break;

730

default:

731

console.log('Unknown message type:', message.type);

732

}

733

}

734

735

private handleReconnect() {

736

if (this.reconnectAttempts >= this.maxReconnectAttempts) {

737

console.error('Max reconnection attempts reached');

738

return;

739

}

740

741

this.reconnectAttempts++;

742

const delay = Math.pow(2, this.reconnectAttempts) * 1000; // Exponential backoff

743

744

console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);

745

746

setTimeout(() => {

747

this.connect(this.getCurrentUserId());

748

}, delay);

749

}

750

751

async disconnect() {

752

if (!this.socketTask) return;

753

754

try {

755

await this.socketTask.close({

756

code: 1000,

757

reason: 'User disconnected'

758

});

759

760

console.log('Chat disconnected successfully');

761

762

} catch (error) {

763

console.error('Error disconnecting chat:', error);

764

}

765

766

this.socketTask = null;

767

}

768

769

// Placeholder methods for UI integration

770

private displayChatMessage(message: any) {

771

console.log(`${message.userId}: ${message.text}`);

772

}

773

774

private showUserJoined(userId: string) {

775

console.log(`${userId} joined the chat`);

776

}

777

778

private showUserLeft(userId: string) {

779

console.log(`${userId} left the chat`);

780

}

781

782

private showTypingIndicator(userId: string, isTyping: boolean) {

783

console.log(`${userId} is ${isTyping ? 'typing' : 'not typing'}`);

784

}

785

786

private getCurrentUserId(): string {

787

return 'current-user-id'; // Get from app state

788

}

789

}

790

791

// Usage

792

const chat = new WebSocketChat();

793

await chat.connect('user123');

794

795

// Send messages

796

chat.sendChatMessage('Hello everyone!');

797

chat.sendTypingIndicator(true);

798

799

// Later disconnect

800

await chat.disconnect();

801

```

802

803

**Usage Examples:**

804

805

```typescript

806

import { addInterceptor, cleanInterceptors, request } from "@tarojs/taro-h5";

807

808

// Add authentication interceptor

809

addInterceptor({

810

request: (config) => {

811

// Add auth token to all requests

812

const token = getStorageSync('authToken');

813

if (token) {

814

config.header = {

815

...config.header,

816

'Authorization': `Bearer ${token}`

817

};

818

}

819

820

// Add request ID for tracking

821

config.header['X-Request-ID'] = Date.now().toString();

822

823

console.log('Outgoing request:', config.url);

824

return config;

825

},

826

827

response: (response) => {

828

// Log successful responses

829

console.log(`Response ${response.statusCode}:`, response.data);

830

831

// Handle global response processing

832

if (response.data && response.data.code === 0) {

833

// Extract data from wrapper

834

response.data = response.data.data;

835

}

836

837

return response;

838

},

839

840

responseError: (error) => {

841

// Handle global error scenarios

842

console.error('Request failed:', error);

843

844

// Handle authentication errors

845

if (error.statusCode === 401) {

846

// Redirect to login

847

console.log('Authentication required, redirecting to login');

848

// Clear invalid token

849

removeStorageSync('authToken');

850

}

851

852

// Handle server errors

853

if (error.statusCode >= 500) {

854

showToast({

855

title: 'Server error, please try again',

856

icon: 'error'

857

});

858

}

859

860

throw error;

861

}

862

});

863

864

// Add base URL interceptor

865

addInterceptor({

866

request: (config) => {

867

// Add base URL if not already absolute

868

if (!config.url.startsWith('http')) {

869

const baseURL = getStorageSync('apiBaseURL') || 'https://api.example.com';

870

config.url = `${baseURL}${config.url}`;

871

}

872

return config;

873

}

874

});

875

876

// Add retry interceptor

877

let retryCount = 0;

878

const MAX_RETRIES = 3;

879

880

addInterceptor({

881

responseError: async (error) => {

882

if (retryCount < MAX_RETRIES && error.statusCode >= 500) {

883

retryCount++;

884

console.log(`Retrying request (${retryCount}/${MAX_RETRIES})`);

885

886

// Wait before retry

887

await new Promise(resolve => setTimeout(resolve, 1000 * retryCount));

888

889

// Retry the original request

890

return request(error.config);

891

}

892

893

retryCount = 0; // Reset on final failure

894

throw error;

895

}

896

});

897

898

// Remove all interceptors when needed

899

function resetInterceptors() {

900

cleanInterceptors();

901

console.log('All interceptors removed');

902

}

903

```

904

905

### Advanced Request Patterns

906

907

Complex request scenarios and best practices for common use cases.

908

909

```typescript

910

// File upload simulation (since actual file upload varies by implementation)

911

const uploadFile = async (file: File, uploadUrl: string) => {

912

// Convert file to base64 for transmission

913

const fileData = await new Promise<string>((resolve) => {

914

const reader = new FileReader();

915

reader.onload = () => resolve(reader.result as string);

916

reader.readAsDataURL(file);

917

});

918

919

const response = await request({

920

url: uploadUrl,

921

method: 'POST',

922

data: {

923

filename: file.name,

924

fileType: file.type,

925

fileData: fileData,

926

size: file.size

927

},

928

header: {

929

'Content-Type': 'application/json'

930

},

931

timeout: 30000 // Extended timeout for uploads

932

});

933

934

return response.data;

935

};

936

937

// Batch requests with concurrency control

938

const batchRequests = async <T>(

939

urls: string[],

940

concurrency: number = 3

941

): Promise<T[]> => {

942

const results: T[] = [];

943

944

for (let i = 0; i < urls.length; i += concurrency) {

945

const batch = urls.slice(i, i + concurrency);

946

const batchPromises = batch.map(url =>

947

request({ url, method: 'GET' }).then(res => res.data)

948

);

949

950

const batchResults = await Promise.all(batchPromises);

951

results.push(...batchResults);

952

}

953

954

return results;

955

};

956

957

// Request with timeout and retry

958

const requestWithRetry = async (

959

options: RequestOption,

960

maxRetries: number = 3,

961

retryDelay: number = 1000

962

): Promise<RequestResult> => {

963

let lastError: any;

964

965

for (let attempt = 1; attempt <= maxRetries; attempt++) {

966

try {

967

return await request({

968

...options,

969

timeout: options.timeout || 5000

970

});

971

} catch (error) {

972

lastError = error;

973

974

if (attempt < maxRetries) {

975

console.log(`Request attempt ${attempt} failed, retrying in ${retryDelay}ms`);

976

await new Promise(resolve => setTimeout(resolve, retryDelay));

977

retryDelay *= 2; // Exponential backoff

978

}

979

}

980

}

981

982

throw lastError;

983

};

984

985

// Cached requests with TTL

986

const requestCache = new Map<string, { data: any, timestamp: number, ttl: number }>();

987

988

const cachedRequest = async (

989

options: RequestOption,

990

ttlMs: number = 300000 // 5 minutes default

991

): Promise<RequestResult> => {

992

const cacheKey = `${options.method || 'GET'}:${options.url}:${JSON.stringify(options.data || {})}`;

993

const cached = requestCache.get(cacheKey);

994

995

if (cached && Date.now() - cached.timestamp < cached.ttl) {

996

console.log('Returning cached response for:', options.url);

997

return {

998

data: cached.data,

999

statusCode: 200,

1000

header: {},

1001

cookies: []

1002

};

1003

}

1004

1005

const response = await request(options);

1006

1007

// Cache successful responses

1008

if (response.statusCode >= 200 && response.statusCode < 300) {

1009

requestCache.set(cacheKey, {

1010

data: response.data,

1011

timestamp: Date.now(),

1012

ttl: ttlMs

1013

});

1014

}

1015

1016

return response;

1017

};

1018

```

1019

1020

### Error Handling

1021

1022

Comprehensive error handling patterns for network requests.

1023

1024

```typescript

1025

// Detailed error handling

1026

const handleApiRequest = async (options: RequestOption) => {

1027

try {

1028

const response = await request(options);

1029

1030

// Check for application-level errors

1031

if (response.data && response.data.error) {

1032

throw new Error(`API Error: ${response.data.error.message}`);

1033

}

1034

1035

return response.data;

1036

1037

} catch (error: any) {

1038

// Network or HTTP errors

1039

if (error.statusCode) {

1040

switch (error.statusCode) {

1041

case 400:

1042

throw new Error('Bad request - please check your data');

1043

case 401:

1044

throw new Error('Authentication required');

1045

case 403:

1046

throw new Error('Access forbidden');

1047

case 404:

1048

throw new Error('Resource not found');

1049

case 429:

1050

throw new Error('Too many requests - please wait');

1051

case 500:

1052

throw new Error('Server error - please try again later');

1053

default:

1054

throw new Error(`HTTP ${error.statusCode}: ${error.errMsg || 'Unknown error'}`);

1055

}

1056

}

1057

1058

// Network connectivity errors

1059

if (error.message?.includes('timeout')) {

1060

throw new Error('Request timeout - please check your connection');

1061

}

1062

1063

if (error.message?.includes('network')) {

1064

throw new Error('Network error - please check your connection');

1065

}

1066

1067

// Re-throw unknown errors

1068

throw error;

1069

}

1070

};

1071

1072

// Usage with proper error handling

1073

async function fetchUserProfile(userId: string) {

1074

try {

1075

const profile = await handleApiRequest({

1076

url: `/api/users/${userId}`,

1077

method: 'GET'

1078

});

1079

1080

return profile;

1081

1082

} catch (error) {

1083

console.error('Failed to fetch user profile:', error.message);

1084

1085

// Show user-friendly error message

1086

showToast({

1087

title: error.message || 'Failed to load profile',

1088

icon: 'error'

1089

});

1090

1091

// Return fallback data or re-throw

1092

return null;

1093

}

1094

}

1095

```

1096

1097

### Callback Pattern Support

1098

1099

Traditional callback pattern support alongside Promise-based usage.

1100

1101

```typescript

1102

// Using callbacks instead of promises

1103

request({

1104

url: 'https://api.example.com/data',

1105

method: 'GET',

1106

success: (response) => {

1107

console.log('Success:', response.data);

1108

console.log('Status:', response.statusCode);

1109

},

1110

fail: (error) => {

1111

console.error('Request failed:', error);

1112

},

1113

complete: (result) => {

1114

console.log('Request completed');

1115

// Called regardless of success or failure

1116

}

1117

});

1118

1119

// Mixed usage - callbacks with promise handling

1120

const response = await request({

1121

url: 'https://api.example.com/data',

1122

method: 'POST',

1123

data: { message: 'Hello' },

1124

success: (res) => {

1125

console.log('Callback success:', res.statusCode);

1126

},

1127

fail: (err) => {

1128

console.log('Callback failure:', err);

1129

}

1130

});

1131

1132

console.log('Promise result:', response.data);

1133

```

1134

1135

## Types

1136

1137

```typescript { .api }

1138

type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';

1139

type DataType = 'json' | 'text' | 'base64';

1140

type ResponseType = 'text' | 'json' | 'arraybuffer';

1141

1142

interface NetworkError extends Error {

1143

statusCode?: number;

1144

errMsg?: string;

1145

config?: RequestOption;

1146

}

1147

```