Tag: WebDev

  • Would you moved away from Express.JS to something like this?

    Imagine a library for node.js that would have been completely decoupled from raw server request and response?

    It may resemble koa a bit over its general vibe, I suppose.

    Instead of raw request and response, only minimal information for each request is provided, and access to to raw request and response avoided, with special hatches to use them when the above interface is not enough (the feature methods on request and responder objects).

    interface Request<TRouteParameters=Record<string,any>> {
       readonly id: string;
       method: string;
       url: string;
       host: string;
       query: ParsedQueryString;
       params:TRouteParameters;
       headers: RequestHeadersBag;
       cookies: RequestCookiesBag;
       contentLength: number;
       contentType: string;
       body: any;
       feature<T>(featureRef:RequestFeatureRef<T>):T;
       tryGetJson():Promise<any>;
       tryGetText():Promise<string>;
       tryGetBuffer():Promise<Buffer>;
       tryGeBodyStream: Readable;
    }
    
    interface Response {
       readonly statusCode: number;
       readonly headers: IResponseHeadersBag;
       readonly cookies: IResponseCookiesBag;
       readonly hasBody: boolean;
       execute(): Promise<void>;
    }  
    
    interface Responder
       readonly responded: boolean;
       status(status: number): Responder;
       setHeader(name:string, value:string):Responder;
       setCookie(cookie:CookieOptions):Responder;   
       
       next(): Promise<IResponse>;
       done(): IResponse;
       noContent() IResponse;
       redirect(url: string, reasonCode: RedirectReasonCode): IResponse;
       html(markup):IResponse;
       json(value:any):IResponse;
       stream(stream:Readable): Promise<IResponse>;
       feature<T>(featureRef:ResponseFeatureRef<T>):T;
    }   
    
    type RequestHandler = function(req:Request, res: Responder) => (Promise<Response>|Response|void);
    
    export type AfterRequestHandler = (req: Request, res:Response) => (Promise<void>|void);
    
    interface Routes {
       before(...handlers: RequestHandler[]): Routes;
       after(...afterHandler:AfterRequestHandler[]):Routes;
       use(path: RouteTemplateOrString, ...handlers: RequestHandler[]): Routes;   
       get(path: RouteTemplateOrString, ...handlers:RequestHandler): Routes;
       post(path: RouteTemplateOrString, ...handlers:RequestHandler): Routes;
       put(path: RouteTemplateOrString, ...handlers:RequestHandler): Routes;
       patch(path: RouteTemplateOrString, ...handlers:RequestHandler): Routes;
       delete(path: RouteTemplateOrString, ...handlers:RequestHandler): Routes;
       options(path: RouteTemplateOrString, ...handlers:RequestHandler): Routes;
       request(method:KnownHttpMethod, path: RouteTemplateOrString, ...handlers: RequestHandler): Routes;
       tryDispatch(request:Request):Promise<IResponse>;
       useRoutes(routes:Routes, prefix?:string):Routes;
    }
    
    //and something like this to use all that:
    export function createRoutes(): Routes;
    export function prepareForHttp(...routes: Routes[]): (req:IncomingMessage, res: ServerResponse) => void;
    
    export function prepareForHttp2(...routes: Routes[]): (req:Http2ServerRequest, res: Http2ServerResponse) => void;
    export function prepareMockRequest(options:MockRequestOptions):Request;
    export function enableRequestFeature<TFeature>(factory:(req:Request) => T): RequestFeatureRef<T>;
    export function enableResponseFeature<TFeature>(factory:(req:Request, res: Responder) => T):ResponseFeatureRef;
    
    export const RawHttp2Request = RequestFeatureRef<Http2ServerRequest>;
    
    export const RawHttp2Response = RequestFeatureRef<Http2ServerResponse>;
    
    export const RawHttp1Request = RequestFeatureRef<IncomingMessage>;
    
    export const RawHttp1Response = RequestFeatureRef<ServerResponse>;
    
    

    I defined the interface above while wrote this post.

    The reason for musing about this theoretical library is sort of being tired of not obvious ways to use same code without dirty hacks for http/1.1, http2, and tests.

    Would you use such library? Or there is such library already?