134 lines
3.8 KiB
JavaScript
134 lines
3.8 KiB
JavaScript
// resources/js/utils/RequestData.js
|
|
import { useHashKeyCache } from '../composables/useHashKeyCache.js';
|
|
|
|
/**
|
|
* Modern implementation of the RequestData pattern.
|
|
* Supports method chaining and integration with HashKeyCache.
|
|
*/
|
|
export class RequestData {
|
|
constructor(withHashCheck = false) {
|
|
this._url = '';
|
|
this._type = 'GET';
|
|
this._data = null;
|
|
this._success = null;
|
|
this._error = null;
|
|
this._fromVarCache = false;
|
|
this._withHashCheck = withHashCheck;
|
|
this._hashCache = useHashKeyCache();
|
|
}
|
|
|
|
/** Set the request URL */
|
|
url(u) {
|
|
this._url = u;
|
|
return this;
|
|
}
|
|
|
|
/** Set the HTTP method (GET, POST, etc.) */
|
|
type(t) {
|
|
this._type = t.toUpperCase();
|
|
return this;
|
|
}
|
|
|
|
/** Set the request payload */
|
|
data(d) {
|
|
this._data = d;
|
|
return this;
|
|
}
|
|
|
|
/** Set the success callback */
|
|
success(callback) {
|
|
this._success = callback;
|
|
return this;
|
|
}
|
|
|
|
/** Set the error callback */
|
|
error(callback) {
|
|
this._error = callback;
|
|
return this;
|
|
}
|
|
|
|
/** Enable or disable cache-first behavior */
|
|
fromVarCache(bool) {
|
|
this._fromVarCache = bool;
|
|
return this;
|
|
}
|
|
|
|
/** Execute the request */
|
|
async go() {
|
|
if (!this._url) {
|
|
console.error('[RequestData] URL is missing');
|
|
return;
|
|
}
|
|
|
|
// 1. Check HashKey/Payload in URL first if applicable
|
|
const urlMatch = this._hashCache.parseHashUrl(this._url);
|
|
if (urlMatch.type !== 'none' && urlMatch.data) {
|
|
if (this._success) this._success(urlMatch.data, urlMatch.value);
|
|
return;
|
|
}
|
|
|
|
// 2. Check Var Cache (in-memory) if requested
|
|
if (this._fromVarCache) {
|
|
const cachedData = this._hashCache.getHashData(this._url);
|
|
if (cachedData) {
|
|
if (this._success) this._success(cachedData);
|
|
// Revalidate in background (Stale-While-Revalidate pattern)
|
|
this._fetchFromServer(true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 3. Perform network request
|
|
return this._fetchFromServer();
|
|
}
|
|
|
|
/** Internal fetch implementation */
|
|
async _fetchFromServer(background = false) {
|
|
try {
|
|
const options = {
|
|
method: this._type,
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
}
|
|
};
|
|
|
|
if (this._data && (this._type === 'POST' || this._type === 'PUT')) {
|
|
options.headers['Content-Type'] = 'application/json';
|
|
options.body = JSON.stringify(this._data);
|
|
}
|
|
|
|
const response = await fetch(this._url, options);
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
|
|
const result = await response.json();
|
|
|
|
// Update cache
|
|
if (this._fromVarCache) {
|
|
this._hashCache.setHashData(this._url, result);
|
|
}
|
|
|
|
// If background revalidation found non-identical data, you might want to call success again
|
|
// or use Pinia to update the UI reactively.
|
|
if (this._success) {
|
|
// For simplicity, we call success again if it's a background fetch
|
|
// but usually you want a way to avoid jitter if data is the same.
|
|
this._success(result);
|
|
}
|
|
|
|
return result;
|
|
} catch (err) {
|
|
if (!background && this._error) {
|
|
this._error(err);
|
|
}
|
|
if (background) {
|
|
console.warn('[RequestData] Background revalidation failed:', err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Wrapper function for easier instantiation */
|
|
export function request(withHashCheck = false) {
|
|
return new RequestData(withHashCheck);
|
|
}
|