The HTTP client for Vue.js providing services for making web requests and handling responses using XMLHttpRequest or JSONP
—
Request and response transformation pipeline for modifying HTTP requests before they are sent and responses before they are processed.
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);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;
};Executes the before callback function if provided in request options, allowing custom pre-request logic.
Implementation:
request.before(request) if request.before is a functionthis binding)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;
});Handles HTTP method emulation for servers that don't support all HTTP methods.
Implementation:
emulateHTTP: true is set and method is PUT, PATCH, or DELETEX-HTTP-Method-Override header with original methodUsage 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: DELETEHandles JSON serialization for requests and deserialization for responses.
Request Processing:
application/jsonResponse Processing:
{ or [)response.body to parsed object or original textUsage 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
});Handles form data encoding and multipart uploads.
Implementation:
emulateJSON: true, converts objects to URL-encoded form dataUsage 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.comApplies default headers based on HTTP method and cross-origin status.
Implementation:
Vue.http.headers[method]Vue.http.headers.commonX-Requested-With: XMLHttpRequest for same-origin requestsUsage 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'});Handles Cross-Origin Resource Sharing (CORS) request configuration.
Implementation:
credentials and crossOrigin optionsUsage Examples:
// CORS request with credentials
this.$http.get('https://api.external.com/data', {
credentials: true,
crossOrigin: true
});Handles JSONP requests for cross-domain API calls.
Implementation:
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);
});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();
});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;
});
});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());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');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;
});
});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