api-core
Version:
Model-based dynamic multi-level APIs for any provider, plus multiple consumption channels
200 lines (173 loc) • 7.35 kB
text/typescript
import {ApiEdgeDefinition} from './ApiEdgeDefinition';
import {ApiEdgeQueryType} from './ApiEdgeQueryType';
import {ApiEdgeQueryContext} from "./ApiEdgeQueryContext";
import {ApiEdgeQueryResponse} from "./ApiEdgeQueryResponse";
import {ApiEdgeError} from "../query/ApiEdgeError";
import {ApiEdgeSchemaTransformation} from "./ApiEdgeSchema";
export class ApiEdgeQuery {
/**
* The API edge to execute the query on.
*/
edge: ApiEdgeDefinition;
/**
* The type of query to execute.
*/
type: ApiEdgeQueryType;
/**
* The list of parameters to use during execution.
*/
context: ApiEdgeQueryContext;
/**
* The list of parameters to use during execution.
*/
body: any;
private originalFields: string[] = [];
/**
* Create a new API Edge Query for the specified API Edge with the specified parameters.
* @param {ApiEdgeDefinition} edge
* @param {ApiEdgeQueryType} type
* @param {ApiEdgeQueryContext} context
* @param {object} body
*/
constructor(edge: ApiEdgeDefinition,
type: ApiEdgeQueryType = ApiEdgeQueryType.Get,
context: ApiEdgeQueryContext = new ApiEdgeQueryContext(),
body: any = null) {
this.edge = edge;
this.type = type;
this.context = context;
this.body = body;
switch (this.type) {
case ApiEdgeQueryType.Get:
if(!this.edge.allowGet) {
throw new ApiEdgeError(405, `Get queries not allowed on edge: ${this.edge.name}`)
}
break;
case ApiEdgeQueryType.Exists:
if(!this.edge.allowExists) {
throw new ApiEdgeError(405, `Exists queries not allowed on edge: ${this.edge.name}`)
}
break;
case ApiEdgeQueryType.Create:
if(!this.edge.allowCreate) {
throw new ApiEdgeError(405, `Create queries not allowed on edge: ${this.edge.name}`)
}
break;
case ApiEdgeQueryType.Delete:
if(!this.edge.allowRemove) {
throw new ApiEdgeError(405, `Delete queries not allowed on edge: ${this.edge.name}`)
}
break;
case ApiEdgeQueryType.Update:
if(!this.edge.allowUpdate) {
throw new ApiEdgeError(405, `Update queries not allowed on edge: ${this.edge.name}`)
}
break;
case ApiEdgeQueryType.Patch:
if(!this.edge.allowPatch) {
throw new ApiEdgeError(405, `Patch queries not allowed on edge: ${this.edge.name}`)
}
break;
case ApiEdgeQueryType.List:
if(!this.edge.allowList) {
throw new ApiEdgeError(405, `List queries not allowed on edge: ${this.edge.name}`)
}
break;
default:
throw new ApiEdgeError(405, "Unsupported Query Type")
}
}
private applySchemaOnInputItem = (item: any) => {
let output = {};
this.edge.schema.transformations.forEach((transformation: ApiEdgeSchemaTransformation) => {
if(transformation.parsedField(item) !== undefined)
transformation.applyToInput(item, output)
});
return output
};
private applySchemaOnItem = (item: any): any => {
let output = {};
if(this.originalFields.length) {
this.edge.schema.transformations.forEach((transformation: ApiEdgeSchemaTransformation) => {
if(this.originalFields.indexOf(transformation.affectedSchemaField) != -1)
transformation.applyToOutput(item, output)
});
}
else {
this.edge.schema.transformations.forEach((transformation: ApiEdgeSchemaTransformation) => {
transformation.applyToOutput(item, output)
});
}
return output
};
/* private applyInputListSchema = (value: ApiEdgeQueryResponse) => {
if(!this.edge.schema)
return value;
value.data = (value.data as any[]).map((item: any) => this.applySchemaOnInputItem(item));
return value
};*/
private applyListSchema = (value: ApiEdgeQueryResponse) => {
if(!this.edge.schema)
return value;
value.data = (value.data as any[]).map((item: any) => this.applySchemaOnItem(item));
return value
};
private applyInputSchema = (value: any): any|Promise<any> => {
if(!this.edge.schema)
return value;
return this.applySchemaOnInputItem(value)
};
private applySchema = (value: ApiEdgeQueryResponse): ApiEdgeQueryResponse|Promise<ApiEdgeQueryResponse> => {
if(!this.edge.schema)
return value;
value.data = this.applySchemaOnItem(value.data);
return value
};
execute = (): Promise<ApiEdgeQueryResponse> => {
if(this.context.fields.length) {
this.originalFields = this.context.fields;
this.context.fields = this.edge.schema.transformFields(this.context.fields);
this.context.filters.forEach(filter => filter.field = this.edge.schema.transformField(filter.field))
//TODO: Support sort-by on renamed fields
}
if(this.body
&& this.type !== ApiEdgeQueryType.Get
&& this.type !== ApiEdgeQueryType.Exists
&& this.type !== ApiEdgeQueryType.Delete
&& this.type !== ApiEdgeQueryType.List)
{
if(!this.context.id) this.context.id = this.body.id;
if(this.edge.schema) {
const result = this.edge.schema.cleanAndValidateModel(
this.body,
this.type === ApiEdgeQueryType.Patch
);
if(!result.valid) {
const errors = result.errors
? result.errors.join(', ')
: '';
throw new ApiEdgeError(422, "Schema Validation Failed: " + errors)
}
}
this.body = this.applyInputSchema(this.body);
}
switch (this.type) {
case ApiEdgeQueryType.Get:
return this.edge.getEntry(this.context).then(this.applySchema);
case ApiEdgeQueryType.Exists:
return this.edge.exists(this.context);
case ApiEdgeQueryType.Create:
return this.edge.createEntry(this.context, this.body).then(this.applySchema);
case ApiEdgeQueryType.Delete:
return this.edge.removeEntry(this.context, this.body).then(this.applySchema);
case ApiEdgeQueryType.Update:
return this.edge.updateEntry(this.context, this.body).then(this.applySchema);
case ApiEdgeQueryType.Patch:
return this.edge.patchEntry(this.context, this.body).then(this.applySchema);
case ApiEdgeQueryType.List:
return this.edge.listEntries(this.context).then(this.applyListSchema);
default:
throw new ApiEdgeError(500, "Unsupported Query Type")
}
}
}