or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

http-client.mdindex.mdinterceptors.mdpromise-service.mdresources.mdurl-processing.md

interceptors.mddocs/

0

# Interceptors

1

2

Request and response transformation pipeline for modifying HTTP requests before they are sent and responses before they are processed.

3

4

## Capabilities

5

6

### Interceptor Interface

7

8

Define custom interceptors to transform requests and responses.

9

10

```javascript { .api }

11

/**

12

* HTTP interceptor interface for request/response transformation

13

*/

14

interface HttpInterceptor {

15

/** Transform request before sending */

16

request?(request: HttpOptions): HttpOptions;

17

/** Transform response before processing */

18

response?(response: HttpResponse): HttpResponse;

19

}

20

21

/**

22

* Functional interceptor that receives request and next callback

23

* @param request - HTTP request options

24

* @param next - Function to call to continue the chain

25

*/

26

type FunctionalInterceptor = (request: HttpOptions, next: NextCallback) => void;

27

28

interface NextCallback {

29

/** Continue to next interceptor or send request */

30

(response?: ResponseCallback): void;

31

}

32

33

interface ResponseCallback {

34

/** Transform response before resolving promise */

35

(response: HttpResponse): HttpResponse;

36

}

37

```

38

39

**Usage Examples:**

40

41

```javascript

42

// Object-style interceptor

43

const authInterceptor = {

44

request(request) {

45

if (!request.headers) request.headers = {};

46

request.headers['Authorization'] = 'Bearer ' + getToken();

47

return request;

48

},

49

50

response(response) {

51

if (response.status === 401) {

52

// Handle unauthorized

53

redirectToLogin();

54

}

55

return response;

56

}

57

};

58

59

// Functional interceptor

60

const loggingInterceptor = function(request, next) {

61

console.log('Sending request to:', request.url);

62

63

next(function(response) {

64

console.log('Received response:', response.status);

65

return response;

66

});

67

};

68

69

// Register interceptors

70

Vue.http.interceptors.push(authInterceptor);

71

Vue.http.interceptors.push(loggingInterceptor);

72

```

73

74

### Built-in Interceptors

75

76

Vue Resource includes several built-in interceptors that are automatically applied in order. Understanding their functionality helps when creating custom interceptors or troubleshooting request/response transformations.

77

78

```javascript { .api }

79

// Built-in interceptor execution order

80

Vue.http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors'];

81

82

// Built-in interceptor implementations

83

Vue.http.interceptor = {

84

before: BeforeInterceptor;

85

method: MethodInterceptor;

86

jsonp: JsonpInterceptor;

87

json: JsonInterceptor;

88

form: FormInterceptor;

89

header: HeaderInterceptor;

90

cors: CorsInterceptor;

91

};

92

```

93

94

#### Before Interceptor

95

96

Executes the `before` callback function if provided in request options, allowing custom pre-request logic.

97

98

**Implementation:**

99

- Calls `request.before(request)` if `request.before` is a function

100

- Executes in the context of the Vue component (`this` binding)

101

- Useful for request logging, authentication tokens, or custom headers

102

103

**Usage Examples:**

104

105

```javascript

106

this.$http.get('/api/users', {

107

before(request) {

108

console.log('About to send request to:', request.url);

109

// 'this' refers to the Vue component

110

this.loading = true;

111

}

112

}).then(response => {

113

this.loading = false;

114

this.users = response.body;

115

});

116

```

117

118

#### Method Interceptor

119

120

Handles HTTP method emulation for servers that don't support all HTTP methods.

121

122

**Implementation:**

123

- When `emulateHTTP: true` is set and method is PUT, PATCH, or DELETE

124

- Changes method to POST and adds `X-HTTP-Method-Override` header with original method

125

- Allows RESTful operations on servers that only support GET/POST

126

127

**Usage Examples:**

128

129

```javascript

130

// Server only supports GET/POST, but you need DELETE

131

this.$http.delete('/api/users/1', {

132

emulateHTTP: true

133

});

134

// Sends: POST /api/users/1 with header X-HTTP-Method-Override: DELETE

135

```

136

137

#### JSON Interceptor

138

139

Handles JSON serialization for requests and deserialization for responses.

140

141

**Request Processing:**

142

- Serializes object bodies to JSON strings when Content-Type is `application/json`

143

- Automatically applies when sending objects as request bodies

144

145

**Response Processing:**

146

- Parses JSON responses based on Content-Type header or content detection

147

- Falls back to content analysis for JSON-like strings (starts with `{` or `[`)

148

- Sets `response.body` to parsed object or original text

149

150

**Usage Examples:**

151

152

```javascript

153

// Request: automatically stringifies object

154

this.$http.post('/api/users', {

155

name: 'John',

156

email: 'john@example.com'

157

});

158

// Body becomes: '{"name":"John","email":"john@example.com"}'

159

160

// Response: automatically parses JSON

161

this.$http.get('/api/users').then(response => {

162

// response.body is already parsed from JSON string to object

163

console.log(response.body.length); // Works directly with array/object

164

});

165

```

166

167

#### Form Interceptor

168

169

Handles form data encoding and multipart uploads.

170

171

**Implementation:**

172

- Removes Content-Type header for FormData bodies (browser sets multipart boundary)

173

- When `emulateJSON: true`, converts objects to URL-encoded form data

174

- Sets appropriate Content-Type for form encoding

175

176

**Usage Examples:**

177

178

```javascript

179

// FormData upload (multipart)

180

const formData = new FormData();

181

formData.append('file', fileInput.files[0]);

182

formData.append('name', 'document.pdf');

183

184

this.$http.post('/api/upload', formData);

185

// Content-Type: multipart/form-data; boundary=...

186

187

// URL-encoded form data

188

this.$http.post('/api/contact', {

189

name: 'John',

190

email: 'john@example.com'

191

}, {

192

emulateJSON: true

193

});

194

// Content-Type: application/x-www-form-urlencoded

195

// Body: name=John&email=john%40example.com

196

```

197

198

#### Header Interceptor

199

200

Applies default headers based on HTTP method and cross-origin status.

201

202

**Implementation:**

203

- Applies method-specific headers from `Vue.http.headers[method]`

204

- Applies common headers from `Vue.http.headers.common`

205

- Adds `X-Requested-With: XMLHttpRequest` for same-origin requests

206

207

**Usage Examples:**

208

209

```javascript

210

// Configure default headers

211

Vue.http.headers.common['Authorization'] = 'Bearer token123';

212

Vue.http.headers.post['Content-Type'] = 'application/json';

213

214

// All requests get Authorization header

215

// POST requests get additional Content-Type header

216

this.$http.post('/api/data', {key: 'value'});

217

```

218

219

#### CORS Interceptor

220

221

Handles Cross-Origin Resource Sharing (CORS) request configuration.

222

223

**Implementation:**

224

- Configures credentials and cross-origin behavior

225

- Works with `credentials` and `crossOrigin` options

226

- Manages browser CORS policy compliance

227

228

**Usage Examples:**

229

230

```javascript

231

// CORS request with credentials

232

this.$http.get('https://api.external.com/data', {

233

credentials: true,

234

crossOrigin: true

235

});

236

```

237

238

#### JSONP Interceptor

239

240

Handles JSONP requests for cross-domain API calls.

241

242

**Implementation:**

243

- Converts requests to JSONP when method is 'JSONP'

244

- Creates script tags for cross-domain requests

245

- Manages callback parameter and cleanup

246

247

**Usage Examples:**

248

249

```javascript

250

// JSONP request (bypasses CORS)

251

this.$http.jsonp('https://api.external.com/data?callback=JSONP_CALLBACK')

252

.then(response => {

253

console.log('JSONP data:', response.body);

254

});

255

```

256

257

### Request Interceptors

258

259

Transform requests before they are sent to the server.

260

261

**Usage Examples:**

262

263

```javascript

264

// Add authentication token

265

Vue.http.interceptors.push(function(request, next) {

266

const token = localStorage.getItem('auth_token');

267

if (token) {

268

if (!request.headers) request.headers = {};

269

request.headers['Authorization'] = `Bearer ${token}`;

270

}

271

next();

272

});

273

274

// Add API version header

275

Vue.http.interceptors.push(function(request, next) {

276

if (!request.headers) request.headers = {};

277

request.headers['Accept'] = 'application/vnd.api+json;version=1';

278

next();

279

});

280

281

// Transform request data

282

Vue.http.interceptors.push(function(request, next) {

283

if (request.method === 'POST' && request.body) {

284

// Wrap data in envelope

285

request.body = {

286

data: request.body,

287

timestamp: Date.now()

288

};

289

}

290

next();

291

});

292

293

// Modify URL based on environment

294

Vue.http.interceptors.push(function(request, next) {

295

if (process.env.NODE_ENV === 'development') {

296

request.url = request.url.replace('/api/', '/dev-api/');

297

}

298

next();

299

});

300

```

301

302

### Response Interceptors

303

304

Transform responses before they are processed by the application.

305

306

**Usage Examples:**

307

308

```javascript

309

// Handle global error responses

310

Vue.http.interceptors.push(function(request, next) {

311

next(function(response) {

312

if (response.status === 401) {

313

// Redirect to login on unauthorized

314

window.location.href = '/login';

315

} else if (response.status === 403) {

316

// Show access denied message

317

alert('Access denied');

318

}

319

return response;

320

});

321

});

322

323

// Unwrap API response envelope

324

Vue.http.interceptors.push(function(request, next) {

325

next(function(response) {

326

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

327

// Extract data from envelope

328

response.body = response.body.data;

329

}

330

return response;

331

});

332

});

333

334

// Add response metadata

335

Vue.http.interceptors.push(function(request, next) {

336

next(function(response) {

337

response.metadata = {

338

requestTime: Date.now(),

339

url: request.url,

340

method: request.method

341

};

342

return response;

343

});

344

});

345

346

// Transform error responses

347

Vue.http.interceptors.push(function(request, next) {

348

next(function(response) {

349

if (!response.ok && response.body && response.body.error) {

350

// Standardize error format

351

response.body = {

352

message: response.body.error.message,

353

code: response.body.error.code,

354

details: response.body.error.details

355

};

356

}

357

return response;

358

});

359

});

360

```

361

362

### Custom Interceptors

363

364

Create reusable interceptors for specific functionality.

365

366

**Usage Examples:**

367

368

```javascript

369

// Retry interceptor

370

function createRetryInterceptor(maxRetries = 3) {

371

return function(request, next) {

372

let attempts = 0;

373

374

function attempt() {

375

attempts++;

376

next(function(response) {

377

if (!response.ok && attempts < maxRetries) {

378

setTimeout(attempt, 1000 * attempts); // Exponential backoff

379

return response;

380

}

381

return response;

382

});

383

}

384

385

attempt();

386

};

387

}

388

389

// Cache interceptor

390

function createCacheInterceptor() {

391

const cache = new Map();

392

393

return function(request, next) {

394

const key = `${request.method}:${request.url}`;

395

396

if (request.method === 'GET' && cache.has(key)) {

397

const cachedResponse = cache.get(key);

398

if (Date.now() - cachedResponse.timestamp < 60000) { // 1 minute cache

399

return Promise.resolve(cachedResponse.response);

400

}

401

}

402

403

next(function(response) {

404

if (request.method === 'GET' && response.ok) {

405

cache.set(key, {

406

response: response,

407

timestamp: Date.now()

408

});

409

}

410

return response;

411

});

412

};

413

}

414

415

// Register custom interceptors

416

Vue.http.interceptors.push(createRetryInterceptor(3));

417

Vue.http.interceptors.push(createCacheInterceptor());

418

```

419

420

### Interceptor Management

421

422

Manage the interceptor chain dynamically.

423

424

```javascript { .api }

425

// Interceptor array (can be modified)

426

Vue.http.interceptors: (HttpInterceptor | string | Function)[];

427

428

// Built-in interceptor registry

429

Vue.http.interceptor: { [name: string]: HttpInterceptor };

430

```

431

432

**Usage Examples:**

433

434

```javascript

435

// Add interceptor by name (uses built-in)

436

Vue.http.interceptors.push('cors');

437

438

// Add custom interceptor

439

Vue.http.interceptors.push(function(request, next) {

440

console.log('Custom interceptor');

441

next();

442

});

443

444

// Remove interceptor

445

const index = Vue.http.interceptors.indexOf('cors');

446

if (index > -1) {

447

Vue.http.interceptors.splice(index, 1);

448

}

449

450

// Clear all interceptors

451

Vue.http.interceptors = [];

452

453

// Reset to defaults

454

Vue.http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors'];

455

456

// Add custom built-in interceptor

457

Vue.http.interceptor.myInterceptor = function(request, next) {

458

// Custom logic

459

next();

460

};

461

462

Vue.http.interceptors.push('myInterceptor');

463

```

464

465

### Error Handling in Interceptors

466

467

Handle errors within interceptors.

468

469

**Usage Examples:**

470

471

```javascript

472

// Catch and transform errors

473

Vue.http.interceptors.push(function(request, next) {

474

next(function(response) {

475

try {

476

if (response.body && typeof response.body === 'string') {

477

response.body = JSON.parse(response.body);

478

}

479

} catch (e) {

480

console.error('Failed to parse JSON response:', e);

481

response.body = {error: 'Invalid JSON response'};

482

}

483

return response;

484

});

485

});

486

487

// Handle network errors

488

Vue.http.interceptors.push(function(request, next) {

489

next(function(response) {

490

if (response instanceof Error) {

491

console.error('Network error:', response.message);

492

return {

493

ok: false,

494

status: 0,

495

statusText: 'Network Error',

496

body: {error: 'Network request failed'}

497

};

498

}

499

return response;

500

});

501

});

502

```

503

504

## Types

505

506

```javascript { .api }

507

interface HttpInterceptor {

508

/** Transform request before sending (optional) */

509

request?(request: HttpOptions): HttpOptions;

510

/** Transform response before processing (optional) */

511

response?(response: HttpResponse): HttpResponse;

512

}

513

514

type FunctionalInterceptor = (request: HttpOptions, next: NextCallback) => void;

515

516

interface NextCallback {

517

/** Continue interceptor chain without response transformation */

518

(): void;

519

/** Continue interceptor chain with response transformation */

520

(responseCallback: ResponseCallback): void;

521

}

522

523

interface ResponseCallback {

524

/** Transform response */

525

(response: HttpResponse): HttpResponse;

526

}

527

528

interface InterceptorRegistry {

529

/** Pre-request processing interceptor */

530

before: HttpInterceptor;

531

/** HTTP method transformation interceptor */

532

method: HttpInterceptor;

533

/** JSONP request handling interceptor */

534

jsonp: HttpInterceptor;

535

/** JSON processing interceptor */

536

json: HttpInterceptor;

537

/** Form data processing interceptor */

538

form: HttpInterceptor;

539

/** Header management interceptor */

540

header: HttpInterceptor;

541

/** CORS handling interceptor */

542

cors: HttpInterceptor;

543

/** Custom interceptors */

544

[name: string]: HttpInterceptor;

545

}

546

```