WakaSync HTTP Integration

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.

The Basics

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>

HTTP Methods

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>

Request Cancellation

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>

Configuration Options

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'

Request Options

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

Advanced Features

Authentication and Custom Headers

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'
            }
        });
    }
});

File Uploads

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);
}

Automatic Retry Logic

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');
}

Query Parameters

// 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

Response Type Control

// 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'
});

HTTP Methods Reference

// 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: {}
});

Cancellation Methods

// 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 Handling

Error Types

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)

Error Handling Pattern

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);
    }
}

Best Practices

  • Use underscore prefix: Store as _http to avoid reactivity overhead on the HTTP client itself
  • Initialize in init(): Create WakaSync instances in the init() lifecycle method
  • Use groupKey for searches: Always cancel previous search requests to prevent race conditions and stale results
  • Handle loading states: Show loading indicators and disable interactive elements during requests
  • Always catch errors: Use try-catch with async/await and handle both cancellation and HTTP errors appropriately
  • Set reasonable timeouts: Default 30s is fine for most APIs, but adjust based on expected response times
  • Check for cancellation: Don't show error messages for AbortError or CancellationError
  • Clean up on destroy: Call this._http.cancelAll() in cleanup if component can be destroyed mid-request
Performance Tip: WakaSync automatically parses JSON responses based on Content-Type headers. Use responseType: 'text' or responseType: 'blob' only when needed to avoid unnecessary parsing overhead.