api-core
Version:
Model-based dynamic multi-level APIs for any provider, plus multiple consumption channels
164 lines (138 loc) • 5.12 kB
text/typescript
import {ApiEdgeDefinition} from "./edge/ApiEdgeDefinition";
import {ApiEdgeMetadata} from "./edge/ApiEdgeMetadata";
import {ApiRequestParser} from "./request/ApiRequestParser";
import {ApiQueryBuilder} from "./query/ApiQueryBuilder";
import {ApiRequest, ApiRequestType} from "./request/ApiRequest";
import {ApiQuery, ApiQueryScope} from "./query/ApiQuery";
import {ApiEdgeRelation, ExportedApiEdgeRelation} from "./relations/ApiEdgeRelation";
import {ApiAction, ApiActionTriggerKind} from "./query/ApiAction";
import {ExternalApiEdge} from "./edge/ExternalApiEdge";
import {ApiResolver} from "./resolver/ApiResolver";
import {LocalApiResolver} from "./resolver/LocalApiResolver";
const pkg = require('../../package.json');
export interface ApiInfo {
title: string
description?: string
termsOfService?: string
contact?: {
name?: string
url?: string
email?: string
}
license?: {
name: string,
url?: string
}
}
export interface ApiMetadata {
info: ApiInfo
version: string
edges: ApiEdgeMetadata[]
relations: ExportedApiEdgeRelation[]
services: ApiService[]
}
export interface ApiService {
name: string
version: string
}
export class Api {
static defaultIdPostfix: string = "Id";
static defaultIdField: string = "id";
url?: string;
info?: ApiInfo;
service: ApiService;
edges: ApiEdgeDefinition[] = [];
relations: ApiEdgeRelation[] = [];
actions: ApiAction[] = [];
private parser: ApiRequestParser;
private queryBuilder: ApiQueryBuilder;
resolver: ApiResolver;
constructor(service: ApiService, ...edges: ApiEdgeDefinition[]) {
this.service = service;
this.edges = edges;
this.parser = new ApiRequestParser(this);
this.queryBuilder = new ApiQueryBuilder(this);
this.resolver = new LocalApiResolver(this)
}
findEdge = (name: string, plural = true) => {
return this.resolver.resolveEdge(name, plural)
};
findRelation(name: string) {
return this.resolver.resolveRelation(name)
}
findRelationOfEdge(edge: string|ApiEdgeDefinition, name: string) {
const edgeName = (edge as any).name || edge;
return this.resolver.resolveRelationOfEdge(edgeName, name)
}
findRelationTo(edge: string|ApiEdgeDefinition, name: string) {
const edgeName = (edge as any).name || edge;
return this.resolver.resolveRelationTo(edgeName, name)
}
findRelationFrom(edge: string|ApiEdgeDefinition, name: string) {
const edgeName = (edge as any).name || edge;
return this.resolver.resolveRelationFrom(edgeName, name)
}
parseRequest = async (requestParts: string[], type: ApiRequestType|null = null) => {
const result = await this.parser.parse(requestParts);
if(type) result.type = type;
return result
};
buildQuery = (request: ApiRequest): ApiQuery => {
const query = this.queryBuilder.build(request);
query.request = request;
return query
};
edge(edge: ApiEdgeDefinition) {
this.edges.push(edge);
edge.api = this;
return this
};
relation(relation: ApiEdgeRelation) {
relation.from.relations.push(relation);
relation.to.relations.push(relation);
this.relations.push(relation);
return this
}
use = (action: ApiAction) => {
this.actions.unshift(action);
return this
};
action = (name: string,
execute: (scope: ApiQueryScope) => Promise<ApiQueryScope>,
triggerKind: ApiActionTriggerKind = ApiActionTriggerKind.OnInput): Api => {
this.actions.unshift(new ApiAction(name, execute, triggerKind));
return this
};
metadata = (): ApiMetadata => {
return {
info: this.info || { title: 'API' },
version: pkg.version,
services: [ this.service ],
edges: this.edges
.filter(edge => !edge.external)
.map(edge => edge.metadata()),
relations: this.relations
.map(relation => relation.toJSON())
}
};
static async fromMetadata(metadata: ApiMetadata): Promise<Api> {
const api = new Api(metadata.services[0] || {});
api.info = metadata.info;
for(let edge of metadata.edges) {
//if(edge.external) continue; -- TODO
api.edge(new ExternalApiEdge(edge, api))
}
for(let relation of metadata.relations) {
api.relation(await ApiEdgeRelation.fromJSON(relation, api))
}
return api
}
async prepare() {
for(let edge of this.edges) {
await edge.prepare(this)
}
}
private extension: { [key: string]: any } = {};
get = (key: string) => this.extension[key];
set = (key: string, value: any) => this.extension[key] = value;
}