WakaSync is an advanced HTTP client designed to work seamlessly with WakaPAC. It provides request cancellation, automatic retry logic, timeout handling, and intelligent response parsing.
Create a WakaSync instance in your component's init() method and use it to make HTTP requests:
<div id="app">
<div data-pac-bind="visible: loading">Loading...</div>
<div data-pac-bind="if: user">
<h2>{{user.name}}</h2>
<p>{{user.email}}</p>
</div>
<div data-pac-bind="visible: error">Error: {{error}}</div>
</div>
<script>
wakaPAC('#app', {
user: null,
loading: false,
error: null,
_http: null,
init() {
// Create HTTP client instance
this._http = new WakaSync({
timeout: 10000,
retries: 1
});
this.loadUser();
},
async loadUser() {
this.loading = true;
this.error = null;
try {
this.user = await this._http.get('/api/user');
} catch (err) {
this.error = err.message;
} finally {
this.loading = false;
}
}
});
</script>
WakaSync provides convenience methods for all standard HTTP verbs:
<div id="app">
<h2>Users</h2>
<ul data-pac-bind="foreach: users" data-pac-item="user">
<li>
{{user.name}}
<button data-pac-bind="click: deleteUser">Delete</button>
</li>
</ul>
<form data-pac-bind="submit: createUser">
<input data-pac-bind="value: newName" placeholder="Name">
<input data-pac-bind="value: newEmail" placeholder="Email">
<button type="submit">Add User</button>
</form>
</div>
<script>
wakaPAC('#app', {
users: [],
newName: '',
newEmail: '',
_http: null,
init() {
this._http = new WakaSync();
this.loadUsers();
},
async loadUsers() {
// GET request
this.users = await this._http.get('/api/users');
},
async createUser() {
// POST with data
const newUser = await this._http.post('/api/users', {
name: this.newName,
email: this.newEmail
});
this.users.push(newUser);
this.newName = '';
this.newEmail = '';
},
async deleteUser(user, index) {
// DELETE request
await this._http.delete(`/api/users/${user.id}`);
this.users.splice(index, 1);
},
async updateUser(userId, changes) {
// PUT - full replacement
await this._http.put(`/api/users/${userId}`, changes);
// PATCH - partial update
await this._http.patch(`/api/users/${userId}`, {
lastLogin: new Date().toISOString()
});
}
});
</script>
Use groupKey to cancel previous requests and prevent race conditions in search interfaces:
<div id="app">
<input data-pac-bind="value: searchQuery" placeholder="Search...">
<div data-pac-bind="visible: searching">Searching...</div>
<ul data-pac-bind="foreach: results" data-pac-item="result">
<li>{{result.title}}</li>
</ul>
</div>
<script>
wakaPAC('#app', {
searchQuery: '',
results: [],
searching: false,
_http: null,
init() {
this._http = new WakaSync();
},
watch: {
async searchQuery(query) {
if (!query) {
this.results = [];
return;
}
// Cancel previous search requests before starting new one
this._http.cancelGroup('search');
this.searching = true;
try {
this.results = await this._http.get('/api/search', {
params: { q: query },
groupKey: 'search' // Tag for cancellation
});
} catch (err) {
// Cancelled requests throw CancellationError/AbortError
if (err.name !== 'AbortError' && err.name !== 'CancellationError') {
console.error('Search failed:', err);
}
} finally {
this.searching = false;
}
}
}
});
</script>
Configure WakaSync globally when creating an instance:
| Option | Default | Description |
|---|---|---|
timeout |
30000 | Request timeout in milliseconds (0 = no timeout) |
retries |
0 | Number of retry attempts on network failure |
retryDelay |
1000 | Delay between retries in milliseconds |
headers |
{} | Default headers applied to all requests |
responseType |
'auto' | Response parsing: 'json', 'text', 'blob', 'response', 'auto' |
Override configuration per-request using the options parameter:
| Option | Description |
|---|---|
groupKey |
Group identifier for batch cancellation |
latestOnly |
Auto-cancel previous requests to the same URL |
params |
Object of query parameters to append to URL |
headers |
Request-specific headers (merged with defaults) |
onSuccess |
Callback function invoked on successful response |
onError |
Callback function invoked on error |
ignoreAbort |
Return undefined instead of throwing on cancellation |
wakaPAC('#app', {
init() {
// Global headers
this._http = new WakaSync({
headers: {
'Authorization': `Bearer ${this.getToken()}`
}
});
},
async loadProtectedData() {
// Request-specific headers (merged with global)
const data = await this._http.get('/api/protected', {
headers: {
'X-Custom-Header': 'value'
}
});
}
});
async uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
formData.append('description', 'My file');
// WakaSync automatically handles FormData
const result = await this._http.post('/api/upload', formData);
console.log('Uploaded:', result);
}
init() {
this._http = new WakaSync({
retries: 3, // Retry up to 3 times
retryDelay: 2000 // Wait 2 seconds between retries
});
}
async loadWithRetry() {
// Automatically retries on network errors (not HTTP errors)
const data = await this._http.get('/api/unstable-endpoint');
}
// Params automatically encoded and appended to URL
const results = await this._http.get('/api/search', {
params: {
q: 'wakaPAC',
limit: 20,
sort: 'relevance'
}
});
// Requests: /api/search?q=wakaPAC&limit=20&sort=relevance
// Download binary file
const blob = await this._http.get('/api/download', {
responseType: 'blob'
});
// Get raw Response object
const response = await this._http.get('/api/data', {
responseType: 'response'
});
// Force text parsing
const html = await this._http.get('/api/page', {
responseType: 'text'
});
// GET request
await http.get(url, options);
// POST request
await http.post(url, data, options);
// PUT request
await http.put(url, data, options);
// PATCH request
await http.patch(url, data, options);
// DELETE request
await http.delete(url, options);
// HEAD request
await http.head(url, options);
// Generic request
await http.request(url, {
method: 'GET',
headers: {},
data: null,
timeout: 5000,
retries: 1,
params: {}
});
// Cancel all pending requests
http.cancelAll();
// Cancel requests in specific group
http.cancelGroup('search');
// Tag requests for cancellation
await http.get('/api/data', { groupKey: 'my-group' });
http.cancelGroup('my-group');
// Auto-cancel previous requests to same URL
await http.get('/api/user/123', { latestOnly: true });
| Error Name | Cause |
|---|---|
AbortError |
Request cancelled via cancelGroup() or timeout |
CancellationError |
Request cancelled internally (superseded, etc.) |
Error (HTTP status) |
HTTP error response (4xx, 5xx status codes) |
try {
const data = await this._http.get('/api/data');
} catch (err) {
// Check if cancelled
if (err.name === 'AbortError' || err.name === 'CancellationError') {
console.log('Request was cancelled');
return;
}
// HTTP error
if (err.response) {
console.error(`HTTP ${err.response.status}:`, err.message);
} else {
// Network error
console.error('Network error:', err.message);
}
}
_http to avoid reactivity overhead on the HTTP client itselfinit() lifecycle methodthis._http.cancelAll() in cleanup if component can be destroyed mid-requestresponseType: 'text' or responseType: 'blob' only when needed to avoid unnecessary parsing overhead.