ngx-http-annotations
Version:
This is a library to angular to use http request via decorator/annotations
369 lines (362 loc) • 17.3 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, APP_INITIALIZER, NgModule } from '@angular/core';
import { delay } from 'rxjs/operators';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
const HTTP_ANNOTATIONS_USE_MOCKS = new InjectionToken('HTTP_ANNOTATIONS_USE_MOCKS');
const HTTP_ANNOTATIONS_USE_DELAY = new InjectionToken('HTTP_ANNOTATIONS_USE_DELAY');
const RESOURCE_METADATA_ROOT = 'resources_metadata';
// @dynamic
const NO_DELAY = 0;
const MOCK_DEFAULT_DELAY = 500;
function observe(annotations) {
return (...args) => HttpRestUtils.decorate('observe', annotations, ...args);
}
function path(annotations) {
return (...args) => {
return HttpRestUtils.decorate('path', annotations, ...args);
};
}
function body(annotations) {
return (...args) => HttpRestUtils.decorate('body', annotations, ...args);
}
function response(annotations) {
return (...args) => HttpRestUtils.decorate('response', annotations, ...args);
}
function query(annotations) {
return (...args) => HttpRestUtils.decorate('query', annotations, ...args);
}
function headers(annotations) {
return (...args) => HttpRestUtils.decorate('headers', annotations, ...args);
}
function produces(annotations) {
return (...args) => HttpRestUtils.decorate('produces', annotations, ...args);
}
var RequestMethodParams;
(function (RequestMethodParams) {
RequestMethodParams["get"] = "Get";
RequestMethodParams["post"] = "Post";
RequestMethodParams["put"] = "Put";
RequestMethodParams["delete"] = "Delete";
RequestMethodParams["options"] = "Options";
RequestMethodParams["head"] = "Head";
RequestMethodParams["patch"] = "Patch";
})(RequestMethodParams || (RequestMethodParams = {}));
class HttpRestUtils {
static decorate(decoratorName, annotations, ...args) {
switch (args.length) {
case 1: {
const [target] = args;
HttpRestUtils.constructMetadata(decoratorName, 'class', annotations, target.prototype);
break;
}
case 2: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [target, __key] = args;
HttpRestUtils.constructMetadata(decoratorName, 'props', annotations, target);
break;
}
case 3:
if (typeof args[2] === 'number') {
const [target, keyName, index] = args;
HttpRestUtils.constructMetadata(decoratorName, 'params', annotations, target, { keyName, index });
break;
}
else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [target, keyName, __descriptor] = args;
HttpRestUtils.constructMetadata(decoratorName, 'methods', annotations, target, { keyName });
break;
}
default:
throw new Error('Decorators are not valid here!');
}
}
/**
* Set up metadata
* @param entityType
* @param value Value of metadata
* @param target Prototype of current object
* @param metaName Decorator name
* @param entityData Entity extra data
*/
static constructMetadata(metaName, entityType, value, target, entityData) {
target[RESOURCE_METADATA_ROOT] = target[RESOURCE_METADATA_ROOT] || {};
target[RESOURCE_METADATA_ROOT][entityType] = target[RESOURCE_METADATA_ROOT][entityType] || {};
const metadataObj = target[RESOURCE_METADATA_ROOT][entityType];
if (entityData && entityData.keyName) {
metadataObj[entityData.keyName] = metadataObj[entityData.keyName] || {};
}
if (entityData && entityData.index != null) {
metadataObj[entityData.keyName][metaName] = metadataObj[entityData.keyName][metaName] || {};
}
switch (entityType) {
case 'class':
metadataObj[metaName] = value;
break;
case 'props':
metadataObj[metaName] = value;
break;
case 'methods':
(entityData) ? metadataObj[entityData.keyName][metaName] = value : undefined;
break;
case 'params':
(entityData) ? metadataObj[entityData.keyName][metaName][value || 'default'] = entityData.index : undefined;
break;
}
target[RESOURCE_METADATA_ROOT][entityType] = metadataObj;
}
static requestMethod(requestMethodName) {
// @dynamic
return (target, key, descriptor) => {
const originalFunction = descriptor.value;
descriptor.value = function (...args) {
const url = HttpRestUtils.collectUrl(target, key, args);
// tslint:disable-next-line:no-shadowed-variable
const body = HttpRestUtils.collectBodyContent(target, key, args);
const search = HttpRestUtils.collectQueryParams(target, key, args);
// tslint:disable-next-line:no-shadowed-variable
const headers = HttpRestUtils.collectHttpHeaders(target, key, args);
const producesType = HttpRestUtils.produce(target, key, args);
// tslint:disable-next-line:no-shadowed-variable
const observe = HttpRestUtils.getHttpClientObserve(target, key, args);
const params = {
body,
params: search,
headers,
responseType: producesType,
observe
};
const newArgs = args;
const responseIndex = HttpRestUtils.collectResponseIndex(target, key, args);
const callConfig = {
url,
requestMethodName,
params,
args: newArgs,
};
if (HttpRestUtils.ifUseMock(callConfig)) { // If "use mock" is true, call original function, to get mock directly from function
return HttpRestUtils.processIfUseMock(responseIndex, args, newArgs, originalFunction);
}
const request = HttpRestUtils.getRequest(callConfig);
if (responseIndex >= 0) {
if (args.length > responseIndex) {
newArgs[responseIndex] = request;
}
else {
newArgs.splice(responseIndex, 0, request);
}
return originalFunction(...newArgs).pipe(HttpRestUtils.getDelay(callConfig));
}
return request.pipe(HttpRestUtils.getDelay(callConfig));
};
};
}
static getRequest(callConfig) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { body: any, ...params } = callConfig.params;
const requestBody = callConfig.params?.body ?? undefined;
switch (callConfig.requestMethodName) {
case RequestMethodParams.get:
return HttpRestUtils.http.get(callConfig.url, callConfig.params);
case RequestMethodParams.post:
return HttpRestUtils.http.post(callConfig.url, requestBody, params);
case RequestMethodParams.put:
return HttpRestUtils.http.put(callConfig.url, requestBody, params);
case RequestMethodParams.delete:
return HttpRestUtils.http.delete(callConfig.url, callConfig.params);
case RequestMethodParams.options:
return HttpRestUtils.http.options(callConfig.url, callConfig.params);
case RequestMethodParams.head:
return HttpRestUtils.http.head(callConfig.url, callConfig.params);
case RequestMethodParams.patch:
return HttpRestUtils.http.patch(callConfig.url, requestBody, params);
default:
return HttpRestUtils.http.request(callConfig.requestMethodName, callConfig.url, callConfig.params);
}
}
static ifUseMock(callConfig) {
let useMock = HttpRestUtils.appInjector?.get(HTTP_ANNOTATIONS_USE_MOCKS, false);
if (typeof useMock === 'function') {
const useMockFunction = useMock;
useMock = useMockFunction(callConfig.url, callConfig.requestMethodName, callConfig.params, callConfig.args);
}
return useMock;
}
static processIfUseMock(responseIndex, args, newArgs, originalFunction) {
if (responseIndex >= 0) {
if (args.length > responseIndex) {
newArgs[responseIndex] = undefined;
}
else {
newArgs.splice(responseIndex, 0, undefined);
}
}
return originalFunction(...newArgs).pipe(this.getDelay(null, MOCK_DEFAULT_DELAY));
}
static getDelay(callConfig, defaultDelay = NO_DELAY) {
let useDelay = HttpRestUtils.appInjector.get(HTTP_ANNOTATIONS_USE_DELAY, defaultDelay);
if (typeof useDelay === 'function' && callConfig) {
const useGetDelayFunction = useDelay;
useDelay = useGetDelayFunction(callConfig.url, callConfig.requestMethodName, callConfig.params, callConfig.args);
}
return delay(useDelay);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static getHttpClientObserve(target, methodName, __args) {
if (target[RESOURCE_METADATA_ROOT].methods
&& target[RESOURCE_METADATA_ROOT].methods[methodName]) {
return target[RESOURCE_METADATA_ROOT].methods[methodName].observe;
}
return undefined;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static produce(target, methodName, __args) {
if (target[RESOURCE_METADATA_ROOT].methods
&& target[RESOURCE_METADATA_ROOT].methods[methodName]) {
return target[RESOURCE_METADATA_ROOT].methods[methodName].produces;
}
return 'json';
}
static collectUrl(target, methodName, args) {
const baseUrl = target[RESOURCE_METADATA_ROOT] && target[RESOURCE_METADATA_ROOT].class
? target[RESOURCE_METADATA_ROOT].class.path
: '';
const methodUrl = target[RESOURCE_METADATA_ROOT].methods && target[RESOURCE_METADATA_ROOT].methods[methodName]
? target[RESOURCE_METADATA_ROOT].methods[methodName].path
: '';
const isRelativePath = `${baseUrl}${methodUrl}`[0] === '/';
const methodUrlWithParams = [baseUrl, methodUrl]
.filter(pathToFilter => pathToFilter)
.join('/')
.split('/')
.map(pathParams => {
if (pathParams[0] === ':') {
const paramName = pathParams.substring(1);
const index = target[RESOURCE_METADATA_ROOT].params
&& target[RESOURCE_METADATA_ROOT].params[methodName]
&& target[RESOURCE_METADATA_ROOT].params[methodName].path
? target[RESOURCE_METADATA_ROOT].params[methodName].path[paramName]
: '';
return args[index];
}
return pathParams;
})
.filter(pathToFilter => pathToFilter)
.join('/');
if (!isRelativePath) {
const [absolutePrefix, ...paths] = methodUrlWithParams.split('/');
return `${absolutePrefix}//${paths.join('/')}`;
}
return `/${methodUrlWithParams}`;
}
static collectBodyContent(target, methodName, args) {
if (!target[RESOURCE_METADATA_ROOT].params
|| !target[RESOURCE_METADATA_ROOT].params[methodName]
|| !target[RESOURCE_METADATA_ROOT].params[methodName].body) {
return undefined;
}
const index = target[RESOURCE_METADATA_ROOT].params[methodName].body.default;
return args[index];
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static collectResponseIndex(target, methodName, __args) {
if (!target[RESOURCE_METADATA_ROOT].params
|| !target[RESOURCE_METADATA_ROOT].params[methodName]
|| !target[RESOURCE_METADATA_ROOT].params[methodName].response) {
return undefined;
}
return target[RESOURCE_METADATA_ROOT].params[methodName].response.default;
}
static collectQueryParams(target, methodName, args) {
if (!target[RESOURCE_METADATA_ROOT].params
|| !target[RESOURCE_METADATA_ROOT].params[methodName]
|| !target[RESOURCE_METADATA_ROOT].params[methodName].query) {
return undefined;
}
const queryParams = {};
const queryParamsObjectIndex = target[RESOURCE_METADATA_ROOT].params[methodName].query.default;
const queryMetadata = target[RESOURCE_METADATA_ROOT].params[methodName].query;
const queryParamsCollection = queryParamsObjectIndex !== undefined
? args[queryParamsObjectIndex]
: Object.keys(queryMetadata).reduce((mergedObj, paramName) => Object.assign(mergedObj, { [paramName]: args[queryMetadata[paramName]] }), {});
Object.keys(queryParamsCollection)
.forEach((paramName) => {
let value = queryParamsCollection[paramName];
if (!Array.isArray(value)) {
value = [value];
}
value.forEach((curParam) => {
return queryParams[paramName] = curParam;
});
});
return queryParams;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static collectHttpHeaders(target, methodName, __args) {
const classHeaders = target[RESOURCE_METADATA_ROOT].class ? target[RESOURCE_METADATA_ROOT].class.headers : {};
const methodHeaders = target[RESOURCE_METADATA_ROOT].methods && target[RESOURCE_METADATA_ROOT].methods[methodName]
? target[RESOURCE_METADATA_ROOT].methods[methodName].headers
: {};
return Object.assign({}, classHeaders, methodHeaders);
}
}
// @dynamic
class NgxHttpAnnotationsModule {
constructor(injector) {
this.injector = injector;
HttpRestUtils.appInjector = this.injector;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: NgxHttpAnnotationsModule, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.6", ngImport: i0, type: NgxHttpAnnotationsModule, imports: [CommonModule, HttpClientModule] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: NgxHttpAnnotationsModule, providers: [
{ provide: APP_INITIALIZER, useFactory: onAppInit, multi: true, deps: [HttpClient] },
{ provide: HTTP_ANNOTATIONS_USE_MOCKS, useValue: false }
], imports: [CommonModule, HttpClientModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: NgxHttpAnnotationsModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, HttpClientModule],
providers: [
{ provide: APP_INITIALIZER, useFactory: onAppInit, multi: true, deps: [HttpClient] },
{ provide: HTTP_ANNOTATIONS_USE_MOCKS, useValue: false }
]
}]
}], ctorParameters: function () { return [{ type: i0.Injector }]; } });
function onAppInit(http) {
return function () {
HttpRestUtils.http = http;
};
}
/* eslint-disable prefer-const */
// noinspection JSUnusedGlobalSymbols
/**
* @deprecated replace HttpRestModule by NgxHttpAnnotationsModule
*/
let HttpRestModule = NgxHttpAnnotationsModule;
let Path = path;
let PathParam = path;
let Body = body(null);
let ResponseObservable = response(null);
let Query = query(null);
let QueryParam = query;
let QueryParams = query;
let Observe = observe;
// Headers
let Headers = headers;
// Produces
let Produces = produces;
// Request methods
let GET = HttpRestUtils.requestMethod(RequestMethodParams.get);
let POST = HttpRestUtils.requestMethod(RequestMethodParams.post);
let PUT = HttpRestUtils.requestMethod(RequestMethodParams.put);
let DELETE = HttpRestUtils.requestMethod(RequestMethodParams.delete);
let OPTIONS = HttpRestUtils.requestMethod(RequestMethodParams.options);
let HEAD = HttpRestUtils.requestMethod(RequestMethodParams.head);
let PATCH = HttpRestUtils.requestMethod(RequestMethodParams.patch);
/**
* Generated bundle index. Do not edit.
*/
export { Body, DELETE, GET, HEAD, HTTP_ANNOTATIONS_USE_DELAY, HTTP_ANNOTATIONS_USE_MOCKS, Headers, HttpRestModule, MOCK_DEFAULT_DELAY, NO_DELAY, NgxHttpAnnotationsModule, OPTIONS, Observe, PATCH, POST, PUT, Path, PathParam, Produces, Query, QueryParam, QueryParams, RESOURCE_METADATA_ROOT, ResponseObservable, onAppInit };
//# sourceMappingURL=ngx-http-annotations.mjs.map