@mbo-ez-angular/ez-http-client
Version:
An ez angular http client inspired by Java OpenFeign Client
467 lines (451 loc) • 19.5 kB
JavaScript
import * as i1 from '@angular/common/http';
import * as i0 from '@angular/core';
import { Injectable } from '@angular/core';
import 'reflect-metadata';
var EzHttpRequestMethod;
(function (EzHttpRequestMethod) {
EzHttpRequestMethod[EzHttpRequestMethod["DELETE"] = 0] = "DELETE";
EzHttpRequestMethod[EzHttpRequestMethod["GET"] = 1] = "GET";
EzHttpRequestMethod[EzHttpRequestMethod["HEAD"] = 2] = "HEAD";
EzHttpRequestMethod[EzHttpRequestMethod["OPTIONS"] = 3] = "OPTIONS";
EzHttpRequestMethod[EzHttpRequestMethod["PATCH"] = 4] = "PATCH";
EzHttpRequestMethod[EzHttpRequestMethod["POST"] = 5] = "POST";
EzHttpRequestMethod[EzHttpRequestMethod["PUT"] = 6] = "PUT";
})(EzHttpRequestMethod || (EzHttpRequestMethod = {}));
function EzHttpClient(apiPath, module) {
return function (targetClass) {
if (!apiPath || apiPath.length === 0) {
apiPath = '';
}
const apiBasePathDescriptor = {
enumerable: true,
configurable: true,
writable: false,
value: apiPath
};
Object.defineProperty(targetClass, 'API_BASE_PATH', apiBasePathDescriptor);
class EzHttpClientDecoratedClass extends targetClass {
constructor(http) {
super();
this.http = http;
const httpClientPropertyDescriptor = {
enumerable: true,
configurable: true,
writable: false,
value: http
};
Object.defineProperty(targetClass, 'HTTP_CLIENT', httpClientPropertyDescriptor);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: EzHttpClientDecoratedClass, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: EzHttpClientDecoratedClass, providedIn: module || 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: EzHttpClientDecoratedClass, decorators: [{
type: Injectable,
args: [{
providedIn: module || 'root'
}]
}], ctorParameters: () => [{ type: i1.HttpClient }] });
return EzHttpClientDecoratedClass;
};
}
function EzHttpClientHeaders(headers) {
return function (targetClass) {
if (!headers) {
headers = {};
}
const apiHeadersDescriptor = {
enumerable: true,
configurable: true,
writable: false,
value: headers
};
const parentClass = Object.getPrototypeOf(targetClass.prototype).constructor;
Object.defineProperty((parentClass.name.toLowerCase() === 'object') ? targetClass : parentClass, 'EZ_HTTP_CLIENT_GLOBAL_HEADERS', apiHeadersDescriptor);
return targetClass;
};
}
/**
* Ez http client common response operators
*
* @param options Common response operators options
* @returns decorator factory
*/
function EzHttpClientCommonResponseOperators(options) {
return function (targetClass) {
if (!options) {
options = { operators: [] };
}
if (!options.operators) {
options.operators = [];
}
const apiHeadersDescriptor = {
enumerable: true,
configurable: true,
writable: false,
value: options
};
const parentClass = Object.getPrototypeOf(targetClass.prototype).constructor;
Object.defineProperty((parentClass.name.toLowerCase() === 'object') ? targetClass : parentClass, 'EZ_HTTP_CLIENT_COMMON_RESPONSE_OPERATORS', apiHeadersDescriptor);
return targetClass;
};
}
const EZ_REQUEST_HEADER_META_KEY = `EzHttpHeader`;
function EzHttpHeader(paramName) {
return function (target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_REQUEST_HEADER_META_KEY, target, methodName) || [];
requestParameters.push({ index: parameterIndex, paramName });
Reflect.defineMetadata(EZ_REQUEST_HEADER_META_KEY, requestParameters, target, methodName);
};
}
const EZ_REQUEST_QUERY_PARAMS_META_KEY = `EzHttpQueryParam`;
function EzHttpQueryParam(paramName) {
return function (target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_REQUEST_QUERY_PARAMS_META_KEY, target, methodName) || [];
requestParameters.push({ index: parameterIndex, paramName });
Reflect.defineMetadata(EZ_REQUEST_QUERY_PARAMS_META_KEY, requestParameters, target, methodName);
};
}
const EZ_REQUEST_PART_DATA_META_KEY = `EzHttpPartData`;
function EzHttpPartData(paramName) {
return function (target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_REQUEST_PART_DATA_META_KEY, target, methodName) || [];
requestParameters.push({ index: parameterIndex, paramName });
Reflect.defineMetadata(EZ_REQUEST_PART_DATA_META_KEY, requestParameters, target, methodName);
};
}
const EZ_REQUEST_PART_FILE_META_KEY = `EzHttpPartFile`;
function EzHttpPartFile(paramName) {
return function (target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_REQUEST_PART_FILE_META_KEY, target, methodName) || [];
requestParameters.push({ index: parameterIndex, paramName });
Reflect.defineMetadata(EZ_REQUEST_PART_FILE_META_KEY, requestParameters, target, methodName);
};
}
const EZ_REQUEST_BODY_META_KEY = `EzHttpRequestBody`;
function EzHttpRequestBody(target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_REQUEST_BODY_META_KEY, target, methodName) || [];
if (requestParameters.length >= 1) {
throw new Error('Only one body can be defined !');
}
requestParameters.push({ index: parameterIndex, paramName: 'body' });
Reflect.defineMetadata(EZ_REQUEST_BODY_META_KEY, requestParameters, target, methodName);
}
const EZ_REQUEST_PARAMS_META_KEY = `EzHttpRequestParam`;
function EzHttpRequestParam(paramName) {
return function (target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_REQUEST_PARAMS_META_KEY, target, methodName) || [];
requestParameters.push({ index: parameterIndex, paramName });
Reflect.defineMetadata(EZ_REQUEST_PARAMS_META_KEY, requestParameters, target, methodName);
};
}
const EZ_RESPONSE_META_KEY = `EzHttpResponse`;
function EzHttpResponse(target, methodName, parameterIndex) {
const requestParameters = Reflect.getOwnMetadata(EZ_RESPONSE_META_KEY, target, methodName) || [];
if (requestParameters.length >= 1) {
throw new Error('Only response mapping parameter can be defined !');
}
requestParameters.push({ index: parameterIndex, paramName: 'response' });
Reflect.defineMetadata(EZ_RESPONSE_META_KEY, requestParameters, target, methodName);
}
// -------------------- DECORATORS --------------------
function EzHttpRequest(httpMethod, options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, httpMethod, options);
};
}
function EzHttpRequestDELETE(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.DELETE, options);
};
}
function EzHttpRequestGET(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.GET, options);
};
}
function EzHttpRequestHEAD(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.HEAD, options);
};
}
function EzHttpRequestOPTIONS(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.OPTIONS, options);
};
}
function EzHttpRequestPATCH(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.PATCH, options);
};
}
function EzHttpRequestPOST(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.POST, options);
};
}
function EzHttpRequestPUT(options) {
return function (target, key, descriptor) {
return apply(target, key, descriptor, EzHttpRequestMethod.PUT, options);
};
}
// -------------------- PRIVATE FUNCTIONS --------------------
/**
* Resolve url to call
*
* @param targetObject The target object (the current object class)
* @param hasParameters Indicate if the url has paameters
* @param ezRequestParams The list of ezRequestParams
* @param options The EzHttpRequest options
* @param args The method arguments
* @returns The resolved url
*/
function resolveUrl(targetObject, hasParameters, ezRequestParams, options, args) {
let uri = options.path;
// resolve uri parameters
if (hasParameters && ezRequestParams.length > 0 && uri && uri.length > 0) {
// replace all parameters
ezRequestParams.forEach(paramDescriptor => {
uri = uri?.replace(`{${paramDescriptor.paramName}}`, args[paramDescriptor.index]);
});
}
// build url
let basePath = targetObject.constructor.API_BASE_PATH || '';
if (basePath.length > 0 && basePath.endsWith('/')) {
basePath = basePath.substring(0, basePath.length - 1);
}
return `${basePath}${uri}`;
}
/**
* Build the http options used pending http call
*
* @param options The EzHttpRequest options
* @param ezQueryParams The list of query params (like ?name=Toto&surname=Titi)
* @param ezRequestHeaders The list of request headers
* @param args The list of method args
* @param targetObject The target object (the current object class)
* @returns The built HttpOptions
*/
function buildHttpOptions(options, ezQueryParams, ezRequestHeaders, args, targetObject) {
const httpOptions = {};
const globalHeaders = targetObject.constructor.EZ_HTTP_CLIENT_GLOBAL_HEADERS;
if (globalHeaders) {
options.headers = Object.assign(globalHeaders, (options.headers || {}));
}
if (options.headers || options.consume) {
httpOptions.headers = options.headers || {};
if (options.consume && options.consume.length > 0) {
stripContentType(httpOptions);
httpOptions.headers['Content-Type'] = options.consume;
}
}
if (ezRequestHeaders?.length) {
httpOptions.headers = httpOptions.headers || {};
ezRequestHeaders.forEach(paramDescriptor => {
const paramValue = args[paramDescriptor.index];
if (paramValue) {
// @ts-ignore: object is possibly 'null'.
httpOptions.headers[paramDescriptor.paramName] = paramValue;
}
});
}
if (options.responseType) {
httpOptions.responseType = options.responseType;
}
// compute http query params
if (ezQueryParams && ezQueryParams.length > 0) {
httpOptions.params = {};
ezQueryParams.forEach(paramDescriptor => {
const paramValue = args[paramDescriptor.index];
if (paramValue) {
// @ts-ignore: object is possibly 'null'.
httpOptions.params[paramDescriptor.paramName] = paramValue;
}
});
}
return httpOptions;
}
/**
* Remove content-type header
*
* @param httpOptions The http options
*/
function stripContentType(httpOptions) {
if (!httpOptions) {
return;
}
for (const key in httpOptions.headers) {
if (key.toLowerCase() === 'content-type') {
delete httpOptions.headers[key];
}
}
}
/**
* Do the http call
*
* @param httpClient The http client instance to use
* @param url The url to call
* @param httpMethod The http method to use
* @param httpOptions The http call options
* @param body The request body
* @param responseOperators rxjs operators to apply to the response
*/
function doCall(httpClient, url, httpMethod, httpOptions, body, responseOperators) {
let responseObservable;
switch (httpMethod) {
case EzHttpRequestMethod.DELETE:
responseObservable = httpClient.delete(url, httpOptions);
break;
case EzHttpRequestMethod.GET:
responseObservable = httpClient.get(url, httpOptions);
break;
case EzHttpRequestMethod.HEAD:
responseObservable = httpClient.head(url, httpOptions);
break;
case EzHttpRequestMethod.OPTIONS:
responseObservable = httpClient.options(url, httpOptions);
break;
case EzHttpRequestMethod.PATCH:
responseObservable = httpClient.patch(url, body, httpOptions);
break;
case EzHttpRequestMethod.POST:
responseObservable = httpClient.post(url, body, httpOptions);
break;
case EzHttpRequestMethod.PUT:
responseObservable = httpClient.put(url, body, httpOptions);
break;
}
if (responseOperators && responseOperators.length > 0) {
responseOperators.forEach(op => responseObservable = responseObservable.pipe(op));
}
return responseObservable;
}
/**
* Apply the task
*
* @param target The target object (the current object class)
* @param key The current method name
* @param descriptor The method descriptor
* @param httpMethod The http method to do
* @param options The ez http request options
* @returns The method updated descriptor
*/
function apply(target, key, descriptor, httpMethod, options) {
if (!options) {
options = {};
}
if (options.path && options.path.length > 0 && !options.path.startsWith('/')) {
options.path = '/' + options.path;
}
else if (!options.path) {
options.path = '';
}
let ezRequestParams = [];
const hasParameters = !!options.path.match(/{\w+}/g);
if (hasParameters) {
ezRequestParams = Reflect.getOwnMetadata(EZ_REQUEST_PARAMS_META_KEY, target, key.toString()) || [];
}
const ezQueryParams = Reflect.getOwnMetadata(EZ_REQUEST_QUERY_PARAMS_META_KEY, target, key.toString()) || [];
const ezRequestHeaders = Reflect.getOwnMetadata(EZ_REQUEST_HEADER_META_KEY, target, key.toString()) || [];
const ezBody = Reflect.getOwnMetadata(EZ_REQUEST_BODY_META_KEY, target, key.toString());
const ezPartDatas = Reflect.getOwnMetadata(EZ_REQUEST_PART_DATA_META_KEY, target, key.toString()) || [];
const ezPartFiles = Reflect.getOwnMetadata(EZ_REQUEST_PART_FILE_META_KEY, target, key.toString()) || [];
const ezResponseMapper = Reflect.getOwnMetadata(EZ_RESPONSE_META_KEY, target, key.toString());
const originalMethod = descriptor.value;
descriptor.value = (...args) => {
// try to get http client instance
const httpClient = target.constructor.HTTP_CLIENT;
if (!httpClient) {
throw new Error('Unable to get http client instance !');
}
const url = resolveUrl(target, hasParameters, ezRequestParams, options, args);
const httpOptions = buildHttpOptions(options, ezQueryParams, ezRequestHeaders, args, target);
const body = ezBody?.length ? args[ezBody[0].index] : {};
const multiPartFormData = buildMultipartFormData(args, ezPartDatas, ezPartFiles, body);
if (!!multiPartFormData) {
stripContentType(httpOptions);
console.log(httpOptions);
}
const commonOperatorsOptions = target.constructor.EZ_HTTP_CLIENT_COMMON_RESPONSE_OPERATORS;
if (!options.responseOperators) {
options.responseOperators = {
operators: []
};
}
const operators = [];
if (commonOperatorsOptions && commonOperatorsOptions.operators && commonOperatorsOptions.operators.length && options.responseOperators.skipGlobalCommonsOperators !== true) {
if (commonOperatorsOptions.before) {
operators.push(...commonOperatorsOptions.operators);
operators.push(...options.responseOperators.operators);
}
else {
operators.push(...options.responseOperators.operators);
operators.push(...commonOperatorsOptions.operators);
}
}
else {
operators.push(...options.responseOperators.operators);
}
const response = doCall(httpClient, url, httpMethod, httpOptions, !!multiPartFormData ? multiPartFormData : body, operators);
if (ezResponseMapper && ezResponseMapper.length > 0) {
args[ezResponseMapper[0].index] = response;
return originalMethod(...args);
}
return response;
};
return descriptor;
}
/**
* Build multipart form data if necessary
*
* @param args Method args
* @param ezPartDatas Part data descriptor array
* @param ezPartFiles Part file descriptor array
* @param body Request body
* @returns FormData or undefined
*/
function buildMultipartFormData(args, ezPartDatas, ezPartFiles, body) {
const buildFormData = (ezPartDatas && !!ezPartDatas.length) || (ezPartFiles && !!ezPartFiles.length);
if (buildFormData) {
const formData = new FormData();
(ezPartDatas || []).forEach(data => {
const value = args[data.index];
// if type of value is not string then build blob otherwise push as is
if (typeof value === 'string') {
formData.append(data.paramName, value);
}
else {
formData.append(data.paramName, new Blob([JSON.stringify(value)], {
type: "application/json"
}));
}
});
(ezPartFiles || []).forEach(data => {
const value = args[data.index];
// if type of value is not File or Blob then ignore
if (value instanceof File || value instanceof Blob) {
formData.append(data.paramName, value);
}
});
if (!!body && Object.keys(body).length > 0) {
// if type of body is not string then build blob otherwise push as is
if (typeof body === 'string') {
formData.append('body', body);
}
else {
formData.append('body', new Blob([JSON.stringify(body)], {
type: "application/json"
}));
}
}
return formData;
}
return undefined;
}
/*
* Public API Surface of ez-http-client-lib
*/
/**
* Generated bundle index. Do not edit.
*/
export { EZ_REQUEST_BODY_META_KEY, EZ_REQUEST_HEADER_META_KEY, EZ_REQUEST_PARAMS_META_KEY, EZ_REQUEST_PART_DATA_META_KEY, EZ_REQUEST_PART_FILE_META_KEY, EZ_REQUEST_QUERY_PARAMS_META_KEY, EZ_RESPONSE_META_KEY, EzHttpClient, EzHttpClientCommonResponseOperators, EzHttpClientHeaders, EzHttpHeader, EzHttpPartData, EzHttpPartFile, EzHttpQueryParam, EzHttpRequest, EzHttpRequestBody, EzHttpRequestDELETE, EzHttpRequestGET, EzHttpRequestHEAD, EzHttpRequestMethod, EzHttpRequestOPTIONS, EzHttpRequestPATCH, EzHttpRequestPOST, EzHttpRequestPUT, EzHttpRequestParam, EzHttpResponse };
//# sourceMappingURL=mbo-ez-angular-ez-http-client.mjs.map