CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-resource

The HTTP client for Vue.js providing services for making web requests and handling responses using XMLHttpRequest or JSONP

Pending
Overview
Eval results
Files

interceptors.mddocs/

Interceptors

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

Capabilities

Interceptor Interface

Define custom interceptors to transform requests and responses.

/**
 * HTTP interceptor interface for request/response transformation
 */
interface HttpInterceptor {
  /** Transform request before sending */
  request?(request: HttpOptions): HttpOptions;
  /** Transform response before processing */  
  response?(response: HttpResponse): HttpResponse;
}

/**
 * Functional interceptor that receives request and next callback
 * @param request - HTTP request options
 * @param next - Function to call to continue the chain
 */
type FunctionalInterceptor = (request: HttpOptions, next: NextCallback) => void;

interface NextCallback {
  /** Continue to next interceptor or send request */
  (response?: ResponseCallback): void;
}

interface ResponseCallback {
  /** Transform response before resolving promise */
  (response: HttpResponse): HttpResponse;
}

Usage Examples:

// Object-style interceptor
const authInterceptor = {
  request(request) {
    if (!request.headers) request.headers = {};
    request.headers['Authorization'] = 'Bearer ' + getToken();
    return request;
  },
  
  response(response) {
    if (response.status === 401) {
      // Handle unauthorized
      redirectToLogin();
    }
    return response;
  }
};

// Functional interceptor
const loggingInterceptor = function(request, next) {
  console.log('Sending request to:', request.url);
  
  next(function(response) {
    console.log('Received response:', response.status);
    return response;
  });
};

// Register interceptors
Vue.http.interceptors.push(authInterceptor);
Vue.http.interceptors.push(loggingInterceptor);

Built-in Interceptors

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.

// Built-in interceptor execution order
Vue.http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors'];

// Built-in interceptor implementations
Vue.http.interceptor = {
  before: BeforeInterceptor;
  method: MethodInterceptor;
  jsonp: JsonpInterceptor;
  json: JsonInterceptor;
  form: FormInterceptor;
  header: HeaderInterceptor;
  cors: CorsInterceptor;
};

Before Interceptor

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

Implementation:

  • Calls request.before(request) if request.before is a function
  • Executes in the context of the Vue component (this binding)
  • Useful for request logging, authentication tokens, or custom headers

Usage Examples:

this.$http.get('/api/users', {
  before(request) {
    console.log('About to send request to:', request.url);
    // 'this' refers to the Vue component
    this.loading = true;
  }
}).then(response => {
  this.loading = false;
  this.users = response.body;
});

Method Interceptor

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

Implementation:

  • When emulateHTTP: true is set and method is PUT, PATCH, or DELETE
  • Changes method to POST and adds X-HTTP-Method-Override header with original method
  • Allows RESTful operations on servers that only support GET/POST

Usage Examples:

// Server only supports GET/POST, but you need DELETE
this.$http.delete('/api/users/1', {
  emulateHTTP: true
});
// Sends: POST /api/users/1 with header X-HTTP-Method-Override: DELETE

JSON Interceptor

Handles JSON serialization for requests and deserialization for responses.

Request Processing:

  • Serializes object bodies to JSON strings when Content-Type is application/json
  • Automatically applies when sending objects as request bodies

Response Processing:

  • Parses JSON responses based on Content-Type header or content detection
  • Falls back to content analysis for JSON-like strings (starts with { or [)
  • Sets response.body to parsed object or original text

Usage Examples:

// Request: automatically stringifies object
this.$http.post('/api/users', {
  name: 'John',
  email: 'john@example.com'
});
// Body becomes: '{"name":"John","email":"john@example.com"}'

// Response: automatically parses JSON
this.$http.get('/api/users').then(response => {
  // response.body is already parsed from JSON string to object
  console.log(response.body.length); // Works directly with array/object
});

Form Interceptor

Handles form data encoding and multipart uploads.

Implementation:

  • Removes Content-Type header for FormData bodies (browser sets multipart boundary)
  • When emulateJSON: true, converts objects to URL-encoded form data
  • Sets appropriate Content-Type for form encoding

Usage Examples:

// FormData upload (multipart)
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('name', 'document.pdf');

this.$http.post('/api/upload', formData);
// Content-Type: multipart/form-data; boundary=...

// URL-encoded form data
this.$http.post('/api/contact', {
  name: 'John',
  email: 'john@example.com'
}, {
  emulateJSON: true
});
// Content-Type: application/x-www-form-urlencoded
// Body: name=John&email=john%40example.com

Header Interceptor

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

Implementation:

  • Applies method-specific headers from Vue.http.headers[method]
  • Applies common headers from Vue.http.headers.common
  • Adds X-Requested-With: XMLHttpRequest for same-origin requests

Usage Examples:

// Configure default headers
Vue.http.headers.common['Authorization'] = 'Bearer token123';
Vue.http.headers.post['Content-Type'] = 'application/json';

// All requests get Authorization header
// POST requests get additional Content-Type header
this.$http.post('/api/data', {key: 'value'});

CORS Interceptor

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

Implementation:

  • Configures credentials and cross-origin behavior
  • Works with credentials and crossOrigin options
  • Manages browser CORS policy compliance

Usage Examples:

// CORS request with credentials
this.$http.get('https://api.external.com/data', {
  credentials: true,
  crossOrigin: true
});

JSONP Interceptor

Handles JSONP requests for cross-domain API calls.

Implementation:

  • Converts requests to JSONP when method is 'JSONP'
  • Creates script tags for cross-domain requests
  • Manages callback parameter and cleanup

Usage Examples:

// JSONP request (bypasses CORS)
this.$http.jsonp('https://api.external.com/data?callback=JSONP_CALLBACK')
  .then(response => {
    console.log('JSONP data:', response.body);
  });

Request Interceptors

Transform requests before they are sent to the server.

Usage Examples:

// Add authentication token
Vue.http.interceptors.push(function(request, next) {
  const token = localStorage.getItem('auth_token');
  if (token) {
    if (!request.headers) request.headers = {};
    request.headers['Authorization'] = `Bearer ${token}`;
  }
  next();
});

// Add API version header
Vue.http.interceptors.push(function(request, next) {
  if (!request.headers) request.headers = {};
  request.headers['Accept'] = 'application/vnd.api+json;version=1';
  next();
});

// Transform request data
Vue.http.interceptors.push(function(request, next) {
  if (request.method === 'POST' && request.body) {
    // Wrap data in envelope
    request.body = {
      data: request.body,
      timestamp: Date.now()
    };
  }
  next();
});

// Modify URL based on environment
Vue.http.interceptors.push(function(request, next) {
  if (process.env.NODE_ENV === 'development') {
    request.url = request.url.replace('/api/', '/dev-api/');
  }
  next();
});

Response Interceptors

Transform responses before they are processed by the application.

Usage Examples:

// Handle global error responses
Vue.http.interceptors.push(function(request, next) {
  next(function(response) {
    if (response.status === 401) {
      // Redirect to login on unauthorized
      window.location.href = '/login';
    } else if (response.status === 403) {
      // Show access denied message
      alert('Access denied');
    }
    return response;
  });
});

// Unwrap API response envelope
Vue.http.interceptors.push(function(request, next) {
  next(function(response) {
    if (response.body && response.body.data) {
      // Extract data from envelope
      response.body = response.body.data;
    }
    return response;
  });
});

// Add response metadata
Vue.http.interceptors.push(function(request, next) {
  next(function(response) {
    response.metadata = {
      requestTime: Date.now(),
      url: request.url,
      method: request.method
    };
    return response;
  });
});

// Transform error responses
Vue.http.interceptors.push(function(request, next) {
  next(function(response) {
    if (!response.ok && response.body && response.body.error) {
      // Standardize error format
      response.body = {
        message: response.body.error.message,
        code: response.body.error.code,
        details: response.body.error.details
      };
    }
    return response;
  });
});

Custom Interceptors

Create reusable interceptors for specific functionality.

Usage Examples:

// Retry interceptor
function createRetryInterceptor(maxRetries = 3) {
  return function(request, next) {
    let attempts = 0;
    
    function attempt() {
      attempts++;
      next(function(response) {
        if (!response.ok && attempts < maxRetries) {
          setTimeout(attempt, 1000 * attempts); // Exponential backoff
          return response;
        }
        return response;
      });
    }
    
    attempt();
  };
}

// Cache interceptor
function createCacheInterceptor() {
  const cache = new Map();
  
  return function(request, next) {
    const key = `${request.method}:${request.url}`;
    
    if (request.method === 'GET' && cache.has(key)) {
      const cachedResponse = cache.get(key);
      if (Date.now() - cachedResponse.timestamp < 60000) { // 1 minute cache
        return Promise.resolve(cachedResponse.response);
      }
    }
    
    next(function(response) {
      if (request.method === 'GET' && response.ok) {
        cache.set(key, {
          response: response,
          timestamp: Date.now()
        });
      }
      return response;
    });
  };
}

// Register custom interceptors
Vue.http.interceptors.push(createRetryInterceptor(3));
Vue.http.interceptors.push(createCacheInterceptor());

Interceptor Management

Manage the interceptor chain dynamically.

// Interceptor array (can be modified)
Vue.http.interceptors: (HttpInterceptor | string | Function)[];

// Built-in interceptor registry
Vue.http.interceptor: { [name: string]: HttpInterceptor };

Usage Examples:

// Add interceptor by name (uses built-in)
Vue.http.interceptors.push('cors');

// Add custom interceptor
Vue.http.interceptors.push(function(request, next) {
  console.log('Custom interceptor');
  next();
});

// Remove interceptor
const index = Vue.http.interceptors.indexOf('cors');
if (index > -1) {
  Vue.http.interceptors.splice(index, 1);
}

// Clear all interceptors
Vue.http.interceptors = [];

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

// Add custom built-in interceptor
Vue.http.interceptor.myInterceptor = function(request, next) {
  // Custom logic
  next();
};

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

Error Handling in Interceptors

Handle errors within interceptors.

Usage Examples:

// Catch and transform errors
Vue.http.interceptors.push(function(request, next) {
  next(function(response) {
    try {
      if (response.body && typeof response.body === 'string') {
        response.body = JSON.parse(response.body);
      }
    } catch (e) {
      console.error('Failed to parse JSON response:', e);
      response.body = {error: 'Invalid JSON response'};
    }
    return response;
  });
});

// Handle network errors
Vue.http.interceptors.push(function(request, next) {
  next(function(response) {
    if (response instanceof Error) {
      console.error('Network error:', response.message);
      return {
        ok: false,
        status: 0,
        statusText: 'Network Error',
        body: {error: 'Network request failed'}
      };
    }
    return response;
  });
});

Types

interface HttpInterceptor {
  /** Transform request before sending (optional) */
  request?(request: HttpOptions): HttpOptions;
  /** Transform response before processing (optional) */
  response?(response: HttpResponse): HttpResponse;
}

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

interface NextCallback {
  /** Continue interceptor chain without response transformation */
  (): void;
  /** Continue interceptor chain with response transformation */
  (responseCallback: ResponseCallback): void;
}

interface ResponseCallback {
  /** Transform response */
  (response: HttpResponse): HttpResponse;
}

interface InterceptorRegistry {
  /** Pre-request processing interceptor */
  before: HttpInterceptor;
  /** HTTP method transformation interceptor */
  method: HttpInterceptor;
  /** JSONP request handling interceptor */
  jsonp: HttpInterceptor;
  /** JSON processing interceptor */
  json: HttpInterceptor;
  /** Form data processing interceptor */
  form: HttpInterceptor;
  /** Header management interceptor */
  header: HttpInterceptor;
  /** CORS handling interceptor */
  cors: HttpInterceptor;
  /** Custom interceptors */
  [name: string]: HttpInterceptor;
}

Install with Tessl CLI

npx tessl i tessl/npm-vue-resource

docs

http-client.md

index.md

interceptors.md

promise-service.md

resources.md

url-processing.md

tile.json