feature - middleware effects combiner
MODIFY
src/effects/effects.combiner.ts
src/effects/effects.combiner.ts
import * as http from 'http';
+import { Observable, merge, forkJoin, of } from 'rxjs';
+import { switchMap, tap } from 'rxjs/operators';
import { StatusCode } from '../util/status-code.util';
-import { Observable, merge } from 'rxjs';
-import { RequestEffect } from './effects.interface';
+import { Effect, EffectResponse } from './effects.interface';
import { HttpRequest, HttpResponse } from '../http.interface';
-export const combineEffects = (...effects: RequestEffect[]) => (
+export const combineEffects = (...effects: Effect<EffectResponse>[]) => (
request$: Observable<HttpRequest>,
response: HttpResponse
) => {
const mappedEffects = effects.map(effect => effect(request$, response));
return merge(...mappedEffects);
};
+
+export const combineMiddlewareEffects = (...effects: Effect<HttpRequest>[]) => (
+ request$: Observable<HttpRequest>,
+ response: HttpResponse
+) => {
+ const mappedEffects = effects.map(effect =>
+ switchMap((mappedReqest: HttpRequest) => effect(of(mappedReqest), response))
+ );
+ return request$.pipe(...mappedEffects);
+};

MODIFY
src/effects/effects.interface.ts
src/effects/effects.interface.ts
@@ -10,5 +10,5 @@ export type EffectResponse = {
export type Effect<T = EffectResponse> = (
request$: Observable<HttpRequest>,
- response?: HttpResponse,
+ response: HttpResponse,
) => Observable<T>;

MODIFY
src/http.interface.ts
src/http.interface.ts
import * as http from 'http';
-export type HttpRequest = http.IncomingMessage;
-export type HttpResponse = http.ServerResponse;
+export interface HttpRequest extends http.IncomingMessage {
+ [key: string]: any;
+}
+
+export interface HttpResponse extends http.ServerResponse {}
+
export type HttpHeaders = Record<string, string>;
export type Http = {

MODIFY
src/http.listener.ts
src/http.listener.ts
@@ -2,23 +2,31 @@ import * as http from 'http';
import { Subject, of } from 'rxjs';
import { defaultIfEmpty, map, tap, switchMap } from 'rxjs/operators';
import { Http, HttpRequest, HttpResponse } from './http.interface';
-import { combineEffects, RequestEffect, EffectResponse } from './effects';
+import { combineEffects, Effect, EffectResponse, combineMiddlewareEffects } from './effects';
import { loggerMiddleware } from './middlewares';
import { handleResponse } from './response';
import { StatusCode } from './util';
-export const httpListener = (...effects: RequestEffect[]) => {
+const middlewares = [
+ loggerMiddleware,
+];
+
+export const httpListener = (...effects: Effect[]) => {
const request$ = new Subject<Http>();
const effect$ = request$
.pipe(
- map(loggerMiddleware),
switchMap(({ req, res }) =>
+ combineMiddlewareEffects(...middlewares)(of(req), res)
+ .pipe(
+ switchMap(req =>
combineEffects(...effects)(of(req), res)
.pipe(
defaultIfEmpty({ status: StatusCode.NOT_FOUND }),
tap(effect => handleResponse(res)(effect))
)
),
+ )
+ )
);
effect$.subscribe();

MODIFY
src/middlewares/logger.middleware.ts
src/middlewares/logger.middleware.ts
import chalk from 'chalk';
-import { Http, HttpResponse } from '../http.interface';
-import { Middleware } from './middleware.interface';
+import { of } from 'rxjs';
+import { map, switchMap, tap } from 'rxjs/operators';
+import { Http, HttpResponse, HttpRequest } from '../http.interface';
+import { Effect } from '../effects/effects.interface';
+import { start } from 'repl';
const getStatusCode = (statusCode: number): string =>
statusCode >= 400
? chalk.red(statusCode.toString())
: chalk.green(statusCode.toString());
-export const loggerMiddleware: Middleware = http => {
- const { info } = console;
- const { req, res } = http;
+const getEndTime = (time: number): number =>
+ Math.round(time * 100) / 100;
- const hrStartTime = process.hrtime();
-
- res.on('finish', () => {
- const endTime = process.hrtime(hrStartTime)[1] / 1000000;
- info(
+const printLog = (method: string, url: string, statusCode: number, startTime: [number, number]) => {
+ const endTime = process.hrtime(startTime)[1] / 1000000;
+ console.info(
`%s %s %s %dms`,
- req.method,
- req.url,
- getStatusCode(res.statusCode),
- Math.round(endTime * 100) / 100
+ method,
+ url,
+ getStatusCode(statusCode),
+ getEndTime(endTime),
);
- });
-
- return http;
};
+
+export const loggerMiddleware: Effect<HttpRequest> = (request$, response) => request$
+ .pipe(
+ tap(request => {
+ const startTime = process.hrtime();
+
+ response.on('finish', () => printLog(
+ request.method!,
+ request.url!,
+ response.statusCode,
+ startTime
+ ));
+ }),
+ );

feature - middleware effects combiner