A robust, event-driven HTTP request service that bridges the XMLHttpRequest Web API with RxJS 9 cold observables and native Promises.
AjaxProvider extends EventTarget (via AjaxProviderMixin) to deliver an event-based, observable HTTP client for modern web components and applications. It allows developers to choose between an async/await Promise interface or a fully reactive RxJS 9 Observable stream.
Modern web development frequently defaults to fetch(), but XMLHttpRequest (XHR) paired with RxJS 9 provides unique capabilities essential for robust enterprise web applications:
- Upload Progress Tracking: Unlike standard
fetch(), XMLHttpRequest exposes xhr.upload.onprogress. This allows AjaxProvider to report real-time percentage updates when uploading large files, FormData, or ArrayBuffer payloads.
- Immediate Socket Teardown: Calling
xhr.abort() instantly terminates the underlying TCP/HTTP connection, guaranteeing zero resource waste upon cancellation.
- Cold Observable Execution: Requests created via
request$() are lazy. The network request is deferred until a subscriber calls .subscribe(). Re-subscribing re-executes the request cleanly.
- Automatic Teardown: Unsubscribing from a
request$() observable automatically triggers xhr.abort(), preventing memory leaks and race conditions.
AjaxProvider provides two primary execution methods depending on your application needs:
| Feature |
generateRequest() (Promise) |
request$() (Observable) |
| Return Type |
Promise<AjaxResponse> |
Observable<AjaxResponse> |
| Primary Use Case |
Standard single-response async/await flows |
Complex reactive flows, streaming & cancellation |
| RxJS Operators |
N/A |
Full support (retry, switchMap, debounceTime) |
| Cancellation |
Not directly cancelable |
Cancelable via unsubscribe() or AbortSignal |
| Progress Events |
Dispatches ajaxprogress events |
Dispatches ajaxprogress & emits progress items |
| Internal Engine |
Wraps request$() via lastValueFrom() |
Native RxJS fromXMLHttpRequest stream |
Note: generateRequest() internally calls lastValueFrom(this.request$()). Both APIs share the exact same underlying RxJS pipeline.
npm install \@blockquote-web-components/ajax-provider
Ideal for straightforward fetch operations using async/await:
import { AjaxProvider } from '\@blockquote-web-components/ajax-provider';
const provider = new AjaxProvider({
url: 'https://httpbingo.org',
path: 'get',
queryParams: { search: 'lit-element' },
});
try {
const response = await provider.generateRequest();
console.log('Response status:', response.status);
console.log('Response body:', response.response);
} catch (error) {
console.error('Request failed:', error.message);
}
Leverage RxJS operators to handle automatic retries on server failures (e.g., HTTP 500):
import { pipe } from 'rxjs/pipe';
import { retry } from 'rxjs/retry';
import { AjaxProvider } from '\@blockquote-web-components/ajax-provider';
const provider = new AjaxProvider({
url: 'https://httpbingo.org',
path: 'status/500',
});
provider
.request$()
[pipe]((values) => values[retry]({ count: 2 }))
.subscribe({
next: (res) => console.log('Success:', res),
error: (err) => console.error('Failed after 3 attempts:', err),
});
Track progress percentages during file uploads or large payload downloads:
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const provider = new AjaxProvider({
url: 'https://httpbingo.org',
path: 'post',
method: 'POST',
body: formData,
includeUploadProgress: true,
includeDownloadProgress: true,
});
provider.addEventListener('ajaxprogress', ({ detail }) => {
const { type, loaded, total } = detail;
const percent = total ? Math.round((loaded / total) * 100) : 0;
console.log(`[${type}] ${percent}% (${loaded}/${total} bytes)`);
});
await provider.generateRequest();
Cancel an in-flight HTTP request cleanly using AbortController:
const controller = new AbortController();
const provider = new AjaxProvider({
url: 'https://httpbingo.org',
path: 'drip',
queryParams: 'duration=5&delay=0&numbytes=1024',
});
provider.request$().subscribe({
next: (res) => console.log('Data:', res),
error: (err) => console.log('Aborted or failed:', err),
}, { signal: controller.signal });
setTimeout(() => controller.abort(), 1000);
Chain dependent requests using EventTarget.when() and RxJS switchMap:
import { pipe } from 'rxjs/pipe';
import { switchMap } from 'rxjs/switch-map';
const requestAuth = new AjaxProvider({ url: 'https://httpbingo.org', path: 'uuid' });
const requestData = new AjaxProvider({ url: 'https://httpbingo.org' });
requestAuth
.when('ajaxresponse')
[pipe]((values) =>
values[switchMap](({ detail }) => {
requestData.path = `anything/${detail.response.uuid}`;
return requestData.request$();
})
)
.subscribe({
next: (result) => console.log('Chained response:', result),
});
requestAuth.generateRequest();
AjaxProvider dispatches standard custom events on its EventTarget context during execution (identically for both generateRequest() and request$()):
ajaxpresend: Fired right before the request is opened.
ajaxprogress: Fired when upload or download progress events occur.
ajaxresponse: Fired when a successful response (status < 400) is received.
ajaxresponseend: Fired after a successful response completes.
ajaxerror: Fired when a request error or HTTP status >= 400 occurs.
ajaxerrorend: Fired after error handling finishes.
url: The base URL for the AJAX request. (string)
path: Path to append to the base URL (e.g. 'users'). (string)
method: The HTTP request method (e.g., 'GET', 'POST', 'PUT', 'DELETE', 'PATCH'). Default: 'GET'. (string)
headers: Custom headers for the request. Default headers:
Accept: 'application/json, text/plain, *\/*; q=0.01'
Content-Type: 'application/json'
body: Request payload (JSON object, FormData, string, Blob, ArrayBuffer, etc.).
queryParams: Query parameters (object or string) appended to the request URL. (Object|string|undefined)
async: Whether to send the request asynchronously. Default: true. (boolean)
timeout: Request timeout in milliseconds. Default: 0 (no timeout). (number)
user: Username for HTTP basic authentication. (string)
password: Password for HTTP basic authentication. (string)
withCredentials: Indicates whether to include cross-site credentials with the request. Default: false. (boolean)
xsrfCookieName: The name of the XSRF cookie. (string)
xsrfHeaderName: The name of the XSRF header. (string)
responseType: The response type ('json', 'text', 'blob', 'arraybuffer', 'document'). Default: 'json'. (string)
includeDownloadProgress: Indicates whether to include download progress events (ajaxprogress). Default: false. (boolean)
includeUploadProgress: Indicates whether to include upload progress events (ajaxprogress). Default: false. (boolean)
avoidBoundary: Set to true to stop delegating boundary management for multipart requests to the browser. Default: false. (boolean)
dispatchEventContext: The context for dispatching custom events. Default: this.
customEventPrefix: Custom event prefix for lifecycle events. Default: 'ajax'. (string)
lastResponse: Stores the last AjaxResponse object received. (AjaxResponse|undefined)
lastError: Stores the last AjaxError object encountered. (AjaxError|undefined)
generateRequest(): Generates and sends the AJAX request, returning a Promise<AjaxResponse>.
request$(): Returns a cold RxJS Observable<AjaxResponse> that executes the AJAX request per subscription.
| Name |
Module |
Package |
AjaxProviderMixin |
/src/AjaxProviderMixin.js |
|
| Name |
Privacy |
Type |
Default |
Description |
Inherited From |
dispatchEventContext |
|
{dispatchEvent(event: CustomEvent): void} | undefined |
this |
The context for dispatching events. |
AjaxProviderMixin |
lastResponse |
|
AjaxResponse<R> | undefined |
undefined |
The last AJAX response object. |
AjaxProviderMixin |
lastError |
|
AjaxError | undefined |
undefined |
The last error object. |
AjaxProviderMixin |
customEventPrefix |
|
string | undefined |
'ajax' |
A custom event prefix for events related to HTTP requests. |
AjaxProviderMixin |
avoidBoundary |
|
boolean | undefined |
false |
Set to `true` to stop delegating the use of boundaries for multipart requests to the browser.
Only change this to `true` if you know what you are doing. |
AjaxProviderMixin |
url |
|
string |
'' |
|
AjaxProviderMixin |
path |
|
string |
'' |
|
AjaxProviderMixin |
body |
|
unknown |
undefined |
|
AjaxProviderMixin |
async |
|
boolean |
true |
|
AjaxProviderMixin |
method |
|
string |
'GET' |
|
AjaxProviderMixin |
_headers |
|
Record<string, string> |
{ Accept: 'application/json, text/plain, */*; q=0.01', 'Content-Type': 'application/json', } |
|
AjaxProviderMixin |
headers |
|
Record<string, string> | undefined |
undefined |
|
AjaxProviderMixin |
timeout |
|
number |
0 |
|
AjaxProviderMixin |
user |
|
string |
'' |
|
AjaxProviderMixin |
password |
|
string |
'' |
|
AjaxProviderMixin |
withCredentials |
|
boolean |
false |
|
AjaxProviderMixin |
xsrfCookieName |
|
string |
'' |
|
AjaxProviderMixin |
xsrfHeaderName |
|
string |
'' |
|
AjaxProviderMixin |
responseType |
|
string |
'' |
|
AjaxProviderMixin |
queryParams |
|
unknown | undefined |
undefined |
|
AjaxProviderMixin |
includeDownloadProgress |
|
boolean |
false |
|
AjaxProviderMixin |
includeUploadProgress |
|
boolean |
false |
|
AjaxProviderMixin |
| Name |
Privacy |
Description |
Parameters |
Return |
Inherited From |
_assignAjaxProviderConfig |
|
Assigns configuration options to the AjaxProvider instance. |
config: AjaxProviderConfig |
void |
|
request$ |
|
Returns a cold Observable that performs the AJAX request on each subscription.
Progress is reported through the `ajaxprogress` event. Errors are reported
through `ajaxerror`/`ajaxerrorend` events before the observable errors. |
|
ColdObservable<AjaxResponse<R>> |
AjaxProviderMixin |
generateRequest |
|
Generates and sends the AJAX request. |
|
Promise<AjaxResponse<R>> |
AjaxProviderMixin |
Private API
| Name |
Privacy |
Description |
Parameters |
Return |
Inherited From |
_assignAjaxRxjsConfig |
private |
Assigns the configuration settings for the AJAX request. |
|
Object |
AjaxProviderMixin |
_joinUrlData |
private |
Joins the base URL and path to create the complete request URL. |
|
string |
AjaxProviderMixin |
_joinHeaders |
private |
Joins the default headers with custom headers. |
formData: unknown |
Object |
AjaxProviderMixin |
_dispatchEvent |
private |
Dispatches a custom event with the specified type and payload. |
type: string, payload: * |
void |
AjaxProviderMixin |
| Kind |
Name |
Declaration |
Module |
Package |
js |
AjaxProvider |
AjaxProvider |
src/AjaxProvider.ts |
|
| Name |
Module |
Package |
dedupeMixin |
|
@open-wc/dedupe-mixin |
| Name |
Type |
Default |
Description |
Base |
T |
|
|
| Name |
Privacy |
Type |
Default |
Description |
Inherited From |
url |
|
string |
'' |
|
|
path |
|
string |
'' |
|
|
body |
|
unknown |
undefined |
|
|
async |
|
boolean |
true |
|
|
method |
|
string |
'GET' |
|
|
_headers |
|
Record<string, string> |
{ Accept: 'application/json, text/plain, */*; q=0.01', 'Content-Type': 'application/json', } |
|
|
headers |
|
Record<string, string> | undefined |
undefined |
|
|
timeout |
|
number |
0 |
|
|
user |
|
string |
'' |
|
|
password |
|
string |
'' |
|
|
withCredentials |
|
boolean |
false |
|
|
xsrfCookieName |
|
string |
'' |
|
|
xsrfHeaderName |
|
string |
'' |
|
|
responseType |
|
string |
'' |
|
|
queryParams |
|
unknown | undefined |
undefined |
|
|
includeDownloadProgress |
|
boolean |
false |
|
|
includeUploadProgress |
|
boolean |
false |
|
|
avoidBoundary |
|
boolean | undefined |
|
|
|
dispatchEventContext |
|
{dispatchEvent(event: CustomEvent): void} | undefined |
|
|
|
customEventPrefix |
|
string | undefined |
|
|
|
lastResponse |
|
AjaxResponse<R> | undefined |
|
|
|
lastError |
|
AjaxError | undefined |
|
|
|
| Name |
Privacy |
Description |
Parameters |
Return |
Inherited From |
request$ |
|
Returns a cold Observable that performs the AJAX request on each subscription.
Progress is reported through the `ajaxprogress` event. Errors are reported
through `ajaxerror`/`ajaxerrorend` events before the observable errors. |
|
ColdObservable<AjaxResponse<R>> |
|
generateRequest |
|
Generates and sends the AJAX request. |
|
Promise<AjaxResponse<R>> |
|
Private API
| Name |
Privacy |
Description |
Parameters |
Return |
Inherited From |
_assignAjaxRxjsConfig |
private |
Assigns the configuration settings for the AJAX request. |
|
Object |
|
_joinUrlData |
private |
Joins the base URL and path to create the complete request URL. |
|
string |
|
_joinHeaders |
private |
Joins the default headers with custom headers. |
formData: unknown |
Object |
|
_dispatchEvent |
private |
Dispatches a custom event with the specified type and payload. |
type: string, payload: * |
void |
|
| Kind |
Name |
Declaration |
Module |
Package |
js |
AjaxProviderMixin |
AjaxProviderMixin |
src/AjaxProviderMixin.ts |
|
| Name |
Privacy |
Type |
Default |
Description |
Inherited From |
originalEvent |
|
Event |
originalEvent |
|
|
xhr |
|
XMLHttpRequest |
xhr |
|
|
request |
|
AjaxRequest |
{ url, headers, body, async: config.async, crossDomain: config.crossDomain, withCredentials: config.withCredentials, method: config.method, timeout: config.timeout, responseType: config.responseType as XMLHttpRequestResponseType, user: config.user, password: config.password, xsrfCookieName: config.xsrfCookieName, xsrfHeaderName: config.xsrfHeaderName, queryParams: config.queryParams, includeDownloadProgress: config.includeDownloadProgress, includeUploadProgress: config.includeUploadProgress, } |
|
|
type |
|
string |
type |
|
|
status |
|
number |
|
|
|
responseType |
|
string |
|
|
|
responseHeaders |
|
Record<string, string> |
|
|
|
response |
|
T |
getXHRResponse(xhr) |
|
|
loaded |
|
number |
|
|
|
total |
|
number |
|
|
|
| Name |
Privacy |
Type |
Default |
Description |
Inherited From |
name |
|
string |
'AjaxError' |
|
|
xhr |
|
XMLHttpRequest |
xhr |
|
|
request |
|
AjaxRequest |
{ url, headers, body, async: config.async, crossDomain: config.crossDomain, withCredentials: config.withCredentials, method: config.method, timeout: config.timeout, responseType: config.responseType as XMLHttpRequestResponseType, user: config.user, password: config.password, xsrfCookieName: config.xsrfCookieName, xsrfHeaderName: config.xsrfHeaderName, queryParams: config.queryParams, includeDownloadProgress: config.includeDownloadProgress, includeUploadProgress: config.includeUploadProgress, } |
|
|
status |
|
number |
|
|
|
responseType |
|
string |
|
|
|
response |
|
unknown |
response |
|
|
| Name |
Privacy |
Type |
Default |
Description |
Inherited From |
name |
|
string |
'AjaxTimeoutError' |
|
AjaxError |
xhr |
|
XMLHttpRequest |
xhr |
|
AjaxError |
request |
|
AjaxRequest |
{ url, headers, body, async: config.async, crossDomain: config.crossDomain, withCredentials: config.withCredentials, method: config.method, timeout: config.timeout, responseType: config.responseType as XMLHttpRequestResponseType, user: config.user, password: config.password, xsrfCookieName: config.xsrfCookieName, xsrfHeaderName: config.xsrfHeaderName, queryParams: config.queryParams, includeDownloadProgress: config.includeDownloadProgress, includeUploadProgress: config.includeUploadProgress, } |
|
AjaxError |
status |
|
number |
|
|
AjaxError |
responseType |
|
string |
|
|
AjaxError |
response |
|
unknown |
response |
|
AjaxError |
| Name |
Description |
Type |
url |
|
|
headers |
|
Record<string, string> |
body |
|
|
| Name |
Description |
Parameters |
Return |
fromXMLHttpRequest |
Creates an `XMLHttpRequest` observable that emits `AjaxResponse` values,
replicating the behavior of the removed `rxjs/ajax` `fromAjax` factory
using the Web Platform Observable (`ColdObservable`) model. |
init: AjaxConfig |
ColdObservable<AjaxResponse<unknown>> |
lastValueFrom |
Resolves with the last value emitted by the observable before completion. |
source$: Subscribable<T> |
Promise<T> |
| Kind |
Name |
Declaration |
Module |
Package |
js |
fromXMLHttpRequest |
fromXMLHttpRequest |
src/fromAjax.ts |
|
js |
lastValueFrom |
lastValueFrom |
src/fromAjax.ts |
|
js |
AjaxResponse |
AjaxResponse |
src/fromAjax.ts |
|
js |
AjaxError |
AjaxError |
src/fromAjax.ts |
|
js |
AjaxTimeoutError |
AjaxTimeoutError |
src/fromAjax.ts |
|
| Kind |
Name |
Declaration |
Module |
Package |
js |
AjaxProvider |
AjaxProvider |
./AjaxProvider.js |
|
js |
AjaxProviderConfig |
AjaxProviderConfig |
./AjaxProvider.js |
|
js |
AjaxProviderMixin |
AjaxProviderMixin |
./AjaxProviderMixin.js |
|
js |
AjaxProviderMixinInterface |
AjaxProviderMixinInterface |
./AjaxProviderMixin.js |
|
js |
ColdObservable |
ColdObservable |
|
rxjs |
js |
AjaxConfig |
AjaxConfig |
./fromAjax.js |
|
js |
AjaxResponse |
AjaxResponse |
./fromAjax.js |
|
js |
AjaxError |
AjaxError |
./fromAjax.js |
|
| Name |
Description |
Type |
isStandardBrowserEnv |
Determines if the code is running in a standard browser environment.
This function checks for specific conditions that indicate whether the code is
running in a standard browser environment, allowing Axios to work in various
environments like web workers, React Native, or NativeScript. |
|
isStandardBrowserWebWorkerEnv |
Determines if the code is running in a standard browser WebWorker environment.
This function checks for specific conditions that indicate whether the code is
running in a standard browser WebWorker environment. It takes into account the
limitations of the `isStandardBrowserEnv` method when working with WebWorkers. |
|
| Name |
Description |
Parameters |
Return |
isFormData |
Determine if a value is a FormData |
thing: * |
boolean |
assignIfDefined |
Utility function to assign a property to an object if the value is defined. |
obj: Object, prop: string, value: * |
void |
| Kind |
Name |
Declaration |
Module |
Package |
js |
isStandardBrowserEnv |
isStandardBrowserEnv |
src/utils.ts |
|
js |
isStandardBrowserWebWorkerEnv |
isStandardBrowserWebWorkerEnv |
src/utils.ts |
|
js |
isFormData |
isFormData |
src/utils.ts |
|
js |
assignIfDefined |
assignIfDefined |
src/utils.ts |
|