Files
bface/src/platform/api.js
2026-05-10 17:56:11 -05:00

151 lines
3.2 KiB
JavaScript

/**
* API Client
* Fetch wrappers for /api/* endpoints with offline support
*/
class APIClient {
constructor(baseURL = '/api') {
this.baseURL = baseURL;
this.interceptors = {
request: [],
response: []
};
}
/**
* Add request interceptor
* @param {Function} interceptor - (config) => config
*/
addRequestInterceptor(interceptor) {
this.interceptors.request.push(interceptor);
}
/**
* Add response interceptor
* @param {Function} interceptor - (response) => response
*/
addResponseInterceptor(interceptor) {
this.interceptors.response.push(interceptor);
}
/**
* Execute request interceptors
* @param {RequestInit} config
* @returns {RequestInit}
*/
_applyRequestInterceptors(config) {
return this.interceptors.request.reduce(
(acc, interceptor) => interceptor(acc),
config
);
}
/**
* Execute response interceptors
* @param {Response} response
* @returns {Response}
*/
_applyResponseInterceptors(response) {
return this.interceptors.response.reduce(
(acc, interceptor) => interceptor(acc),
response
);
}
/**
* Resolve an endpoint against the configured API base URL
* @param {string} endpoint
* @returns {string}
*/
resolveURL(endpoint = '') {
return `${this.baseURL}${endpoint}`;
}
/**
* Replace the configured API base URL for future requests.
* @param {string} baseURL
*/
setBaseURL(baseURL = '/api') {
this.baseURL = baseURL || '/api';
}
/**
* Make API request
* @param {string} endpoint
* @param {RequestInit} options
* @returns {Promise<Response>}
*/
async request(endpoint, options = {}) {
const url = this.resolveURL(endpoint);
const config = this._applyRequestInterceptors({
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
try {
const response = await fetch(url, config);
return this._applyResponseInterceptors(response);
} catch (error) {
// TODO: Implement offline queue management
throw error;
}
}
/**
* GET request
* @param {string} endpoint
* @param {RequestInit} options
* @returns {Promise<Response>}
*/
async get(endpoint, options = {}) {
return this.request(endpoint, { ...options, method: 'GET' });
}
/**
* POST request
* @param {string} endpoint
* @param {any} data
* @param {RequestInit} options
* @returns {Promise<Response>}
*/
async post(endpoint, data, options = {}) {
return this.request(endpoint, {
...options,
method: 'POST',
body: JSON.stringify(data)
});
}
/**
* PUT request
* @param {string} endpoint
* @param {any} data
* @param {RequestInit} options
* @returns {Promise<Response>}
*/
async put(endpoint, data, options = {}) {
return this.request(endpoint, {
...options,
method: 'PUT',
body: JSON.stringify(data)
});
}
/**
* DELETE request
* @param {string} endpoint
* @param {RequestInit} options
* @returns {Promise<Response>}
*/
async delete(endpoint, options = {}) {
return this.request(endpoint, { ...options, method: 'DELETE' });
}
}
// Export singleton instance
export const api = new APIClient();