@scefira/dfw-nodejs
Version:
301 lines (253 loc) • 9.59 kB
text/typescript
import DFWModule from "./DFWModule";
import { DFWScheme } from "../..";
import { Request, Response, Router, NextFunction, RequestHandler } from "express";
import axios, { AxiosRequestConfig, AxiosResponse, AxiosStatic } from "axios";
import { isString, isObject } from "util";
import SecurityManager from "./SecurityManager";
import { UploadOptions, UploadConfig } from "./UploadManager";
export type BootCallback = (dfw:DFWScheme,boot:any)=>Promise<any>;
export type APIMethods = "get"|"put"|"post"|"delete"|"options"|"link";
export type APIFunction = ((dfw:DFWScheme)=>Promise<any>)|((dfw:DFWScheme)=>any);
export class APIListener{
public caller:APIFunction;
public config:DFWListenerConfig;
constructor(f:APIFunction,cfg?:DFWListenerConfig){
this.caller = f;
this.config = cfg?cfg:{};
}
}
export default class APIManager extends DFWModule{
private bootCallbacks:BootCallback[] = [
/** add default callback on each APIManager instance */
async (dfw,boot:DFWBoot)=>{
boot.session = {
isLogged: dfw.session.isLogged,
nick: dfw.session.isLogged?dfw.session.model.user!.nick:undefined,
email:dfw.session.isLogged?dfw.session.model.user!.email:undefined,
credentials:[],
access:[]
}
if(dfw.session.isLogged && dfw.session.model.user){ // if is user logged, then we load the access and credentials and send it to boot state
dfw.session.model.user.credentials.forEach((c)=>{
let {name,description,id} = c;
boot.session.credentials.push({name,description,id});
if(c.access !== undefined){
c.access.forEach((a)=>{
let {name,description,id} = a;
boot.session.credentials.push({name,description,id});
})
}
})
}
}
];
/**
*
* @param dfw
*/
public async touchAsync(dfw:DFWScheme){
dfw.api.bootAsync = async ()=>{
return await this.getBootAsync(dfw);
}
dfw.api.error = (description?:string,reference?:string)=>{
dfw.response.status(400);
dfw.response.statusMessage = "ERROR";
return { "error" : description , ref: reference };
}
dfw.api.success = (data?:any)=>{
return data?data:"";
}
dfw.api.response = (data:any)=>{
this.response(dfw,data);
}
dfw.api.notFound = (description?:string)=>{
dfw.response.status(404);
return { "message" : description };
}
}
/**
*
* @param dfw
*/
public async getBootAsync(dfw:DFWScheme):Promise<any>{
let result = {};
for(let i = 0; i < this.bootCallbacks.length; i++){
await this.bootCallbacks[i](dfw,result);
}
return result;
}
/**
*
* @param bootc
*/
public addBootCallback(bootc:BootCallback){
this.bootCallbacks.push(bootc);
}
/**
*
* @param dfw
*/
public response(dfw:DFWScheme,data:{}){
dfw.response.json(data);
}
/**
* fetch data to the server
* @param path
* @param config
*/
public fetch(path:string,config?:AxiosRequestConfig):Promise<AxiosResponse>{
return axios.get(path,config);
}
/**
* add an API listener
* @param path
* @param f
* @param method
* @param router
*/
public addListener(path:string,f:APIFunction,cfg?:DFWListenerConfig|APIMethods){
if(this.DFWInstance.server === undefined){
console.error("> you need to start DFW express server (DFW.startServer) to add an API listener");
return;
}
let {method, router, middleware,...settings} = isObject(cfg)?cfg as DFWListenerConfig:{} as DFWListenerConfig;
if(settings === undefined) settings = {};
if(method === undefined) method = isString(cfg)?cfg:"get";
if(router === undefined) router = this.DFWInstance.server;
if(middleware === undefined) middleware = [];
middleware.push(this.DFWInstance.middleware);
// Validation of the rules in DFWListenerConfig if fails locks the process
middleware.push((req:Request,res:Response,next:NextFunction)=>{
this.validateListenerConfigRules(req.dfw!,settings).then((status)=>{
if(status === true){
next();
}
}).catch((e)=>{
this.response(req.dfw!, req.dfw!.api.error(`${e}`,"dfw"));
})
});
// Third party middlewares validated
if(settings.security !== undefined && settings.security.uploads){
let uploadCfg:UploadConfig = (isObject( settings.security.uploads))?settings.security.uploads as UploadConfig:{};
middleware.push(this.DFWInstance.modules.uploadManager.makeUploadMiddleware(uploadCfg));
}
// Main DFW library middleware
middleware.push((req:Request,res:Response,next:NextFunction)=>{
let dfw:DFWScheme = req.dfw!;
f(dfw).then((data)=>{
this.response(dfw,data);
}).catch((e)=>{
console.log(e);
this.response(dfw, dfw.api.error(`${e}`,"api"));
});
});
router
}
/**
* synonym of addUploadListener from UploadManager
* @param path
* @param dfwConfig
* @param uploadConfig
*/
public addUploadListener(path:string,dfwConfig:DFWListenerConfig = {},uploadConfig?:UploadOptions){
if(dfwConfig.security === undefined) dfwConfig.security = {};
if(dfwConfig.security!.uploads === undefined) dfwConfig.security!.uploads = true;
this.DFWInstance.modules.APIManager.addListener(path, async (dfw:DFWScheme)=>{
let file = await dfw.file.flushUploadAsync(dfw.request.files["file"] as any,uploadConfig);
if(!file){
return dfw.api.error();
}else{
return dfw.api.success({ file: await this.DFWInstance.modules.uploadManager.getFileRecordDataAsync(file) });
}
},Object.assign({},dfwConfig,{method:"post"}));
this.DFWInstance.modules.APIManager.addListener(path, async (dfw:DFWScheme)=>{
dfw.response.set({
'Access-Control-Allow-Methods': 'OPTIONS, POST',
'Access-Control-Allow-Headers': 'Content-Type'
});
},"options");
}
/**
* @returns boolean true if checking is succeed or false if one rule fail
*/
public async validateListenerConfigRules(dfw:DFWScheme,settings:DFWListenerConfig){
if(settings.security !== undefined ){ // Modulo de seguridad
if(settings.security.session !== undefined && ! await dfw.security.checkRuleAsync(SecurityManager.RULE_LOGGED_SESSION,settings.security.session)){
dfw.api.response(dfw.api.error(SecurityManager.LABEL_RULE_LOGGED_SESSION));
return false;
}
if(settings.security.credentials !== undefined && ! await dfw.security.checkRuleAsync(SecurityManager.RULE_CREDENTIAL,settings.security.credentials)){
dfw.api.response(dfw.api.error(SecurityManager.LABEL_RULE_CREDENTIAL));
return false;
}
if(settings.security.access !== undefined && ! await dfw.security.checkRuleAsync(SecurityManager.RULE_ACCESS,settings.security.access)){
dfw.api.response(dfw.api.error(SecurityManager.LABEL_RULE_ACCESS));
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Return an instance of axios
*/
public static axios:AxiosStatic = axios;
}
/**
* Configuration for listener in DFW
*/
export interface DFWListenerConfig{
method?:APIMethods;
router?:Router;
middleware?:RequestHandler[];
security?:{
session?:boolean;
credentials?:string|string[];
access?:string|string[];
uploads?:boolean|UploadConfig;
}
validation?:{
body?:string[],
query?:string[],
}
}
export type DFWBasicBoot = {
session:{
isLogged:boolean,
nick?:string,
email?:string,
credentials:{
id:number,
name:string,
description?:string,
}[],
access?:{
id:number,
name:string,
description?:string,
}[]
}
}
export type DFWBoot<T extends {} = DFWBasicBoot> = T & DFWBasicBoot;
export interface DFWAPISchema{
/**
*
*/
bootAsync: () => Promise<{}>;
/**
*
*/
error: (description?:string,ref?:string) => any;
/**
*
*/
success: (data?:any)=>any;
/**
*
*/
response: (data:any)=>void;
/**
*
*/
notFound: (description?:string)=>void;
}