Skip to content

Instantly share code, notes, and snippets.

@sinchang
Forked from maxgaurav/functional-http-service.ts
Created September 15, 2023 11:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sinchang/d24704ab18c34c434028f8a1b80a3510 to your computer and use it in GitHub Desktop.
Save sinchang/d24704ab18c34c434028f8a1b80a3510 to your computer and use it in GitHub Desktop.
A Interceptor system for raw ajax on rxjs to get same functionality as in angular http client interceptor.
import { ajax, AjaxConfig, AjaxResponse } from 'rxjs/ajax';
import { from, Observable, of, OperatorFunction, switchMap } from 'rxjs';
export type BeforeInterceptors = (config: AjaxConfig) => Promise<AjaxConfig> | AjaxConfig | Observable<AjaxConfig>;
export type AfterInterceptors<T extends any = any> = (response: AjaxResponse<T>) => Observable<AjaxResponse<T>> | AjaxResponse<T> | Promise<AjaxResponse<T>>;
const BEFORE_INTERCEPTORS: BeforeInterceptors[] = [];
const AFTER_INTERCEPTORS: AfterInterceptors[] = [];
interface ConfigInterceptor {
beforeInterceptors?: BeforeInterceptors[];
afterInterceptors?: AfterInterceptors[];
}
/**
* Get request
* @param url
* @param config
*/
export function getRequest<T>(url: string, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return executeRequest({url, method: 'GET', ...config});
}
/**
* Post request
* @param url
* @param body
* @param config
*/
export function postRequest<T>(url: string, body: any, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return executeRequest({url, body, method: 'POST', ...config});
}
/**
* Post request
* @param url
* @param body
* @param config
*/
export function putRequest<T>(url: string, body: any, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return executeRequest({url, method: 'PUT', ...config});
}
/**
* Put request
* @param url
* @param body
* @param config
*/
export function patchRequest<T>(url: string, body: any, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return executeRequest({url, method: 'PATCH', ...config});
}
/**
* Delete request
* @param url
* @param config
*/
export function deleteRequest<T>(url: string, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return executeRequest({url, method: 'DELETE', ...config});
}
export const configInterceptors = (config: ConfigInterceptor) => {
(config.beforeInterceptors || []).forEach(interceptor => BEFORE_INTERCEPTORS.push(interceptor));
(config.afterInterceptors || []).forEach(interceptor => AFTER_INTERCEPTORS.push(interceptor));
}
function executeRequest<T>(config: AjaxConfig): Observable<AjaxResponse<T>> {
const beforeInterceptors: OperatorFunction<AjaxConfig, AjaxConfig>[] = BEFORE_INTERCEPTORS.map(interceptor => switchMap((requestConfig: AjaxConfig) => {
const result = interceptor(requestConfig);
if (result instanceof Promise) {
return from(result);
}
if (result instanceof Observable) {
return result;
}
return of(result);
}));
let execution: Observable<AjaxConfig> | Observable<AjaxResponse<T>> = of(config);
for (const interceptor of beforeInterceptors) {
execution = execution.pipe(interceptor);
}
execution = execution
.pipe<AjaxResponse<T>>(switchMap((requestConfig) => ajax<T>(requestConfig)));
const afterInterceptors: OperatorFunction<AjaxResponse<T>, AjaxResponse<T>>[] = AFTER_INTERCEPTORS.map(interceptor => switchMap((response: AjaxResponse<T>) => {
const result = interceptor(response);
if (result instanceof Promise) {
return from(result);
}
if (result instanceof Observable) {
return result;
}
return of(result);
}));
for (const interceptor of afterInterceptors) {
execution = execution.pipe(interceptor);
}
return execution;
}
import { ajax, AjaxConfig, AjaxResponse } from 'rxjs/ajax';
import { from, map, Observable, of, OperatorFunction, switchMap } from 'rxjs';
export type BeforeInterceptors = (config: AjaxConfig) => Promise<AjaxConfig> | AjaxConfig | Observable<AjaxConfig>;
export type AfterInterceptors<T extends any = any> = (response: AjaxResponse<T>) => Observable<AjaxResponse<T>> | AjaxResponse<T> | Promise<AjaxResponse<T>>;
export class HttpService {
protected ajaxInstance;
constructor(protected beforeInterceptors: BeforeInterceptors[] = [], protected afterInterceptors: AfterInterceptors[] = [] ) {
this.ajaxInstance = ajax;
}
/**
* Get request
* @param url
* @param config
*/
public get<T>(url: string, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return this.executeRequest({url, method: 'GET', ...config});
}
/**
* Post request
* @param url
* @param body
* @param config
*/
public post<T>(url: string, body: any, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return this.executeRequest({url, body, method: 'POST', ...config});
}
/**
* Post request
* @param url
* @param body
* @param config
*/
public put<T>(url: string, body: any, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return this.executeRequest({url, method: 'PUT', ...config});
}
/**
* Put request
* @param url
* @param body
* @param config
*/
public patch<T>(url: string, body: any, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return this.executeRequest({url, method: 'PATCH', ...config});
}
/**
* Delete request
* @param url
* @param config
*/
public delete<T>(url: string, config: Omit<AjaxConfig, 'url' | 'body'>): Observable<AjaxResponse<T>> {
return this.executeRequest({url, method: 'DELETE', ...config});
}
protected executeRequest<T>(config: AjaxConfig): Observable<AjaxResponse<T>> {
const beforeInterceptors: OperatorFunction<AjaxConfig, AjaxConfig>[] = this.beforeInterceptors.map(interceptor => switchMap((requestConfig: AjaxConfig) => {
const result = interceptor(requestConfig);
if (result instanceof Promise) {
return from(result);
}
if (result instanceof Observable) {
return result;
}
return of(result);
}));
let execution: Observable<AjaxConfig> | Observable<AjaxResponse<T>> = of(config);
for (const interceptor of beforeInterceptors) {
execution = execution.pipe(interceptor);
}
execution = execution
.pipe<AjaxResponse<T>>(switchMap((requestConfig) => this.ajaxInstance<T>(requestConfig)));
const afterInterceptors: OperatorFunction<AjaxResponse<T>, AjaxResponse<T>>[] = this.afterInterceptors.map(interceptor => switchMap((response: AjaxResponse<T>) => {
const result = interceptor(response);
if (result instanceof Promise) {
return from(result);
}
if (result instanceof Observable) {
return result;
}
return of(result);
}));
for (const interceptor of afterInterceptors) {
execution = execution.pipe(interceptor);
}
return execution;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment