improvement - resolved issue with circular dependency problem
MODIFY
example/controllers.ts
example/controllers.ts
import { filter, map } from 'rxjs/operators';
-import { Effect } from '../src';
-import { StatusCode } from '../src/util';
+import { Effect, HttpStatus, ofType } from '../src';
export const root$: Effect = request$ => request$
.pipe(
filter(req => req.url === '/'),
+ ofType('GET'),
map(req => ({
- status: StatusCode.OK,
+ status: HttpStatus.OK,
body: { data: `API root @ ${req.url}` },
}))
);
@@ -14,9 +14,9 @@ export const root$: Effect = request$ => request$
export const hello$: Effect = request$ => request$
.pipe(
filter(req => req.url === '/hello'),
- filter(req => req.method === 'POST'),
+ ofType('POST'),
map(req => ({
- status: StatusCode.OK,
+ status: HttpStatus.OK,
body: { data: `Hello, ${req.body.data}! @ ${req.url}` },
}))
);

MODIFY
src/effects/effects.interface.ts
src/effects/effects.interface.ts
import { Observable } from 'rxjs';
-import { HttpRequest, HttpResponse } from '../http.interface';
-import { StatusCode } from '../util';
+import { HttpRequest, HttpResponse, HttpStatus } from '../http.interface';
export interface EffectResponse {
- status: StatusCode;
+ status: HttpStatus;
body?: object;
headers?: Record<string, string>;
}

DELETE
src/effects/index.ts
-export * from './effects.combiner';
-export * from './effects.interface';

MODIFY
src/http.interface.ts
src/http.interface.ts
@@ -11,6 +11,17 @@ export type HttpHeaders = Record<string, string>;
export type HttpMethod = 'POST' | 'PUT' | 'PATCH' | 'GET' | 'HEAD' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE';
+export enum HttpStatus {
+ OK = 200,
+ BAD_REQUEST = 400,
+ UNAUTHORIZED = 401,
+ FORBIDDEN = 403,
+ NOT_FOUND = 404,
+ FAILED_DEPENDENCY = 424,
+ INTERNAL_SERVER_ERROR = 500,
+ SERVICE_UNAVAILABLE = 503,
+}
+
export type Http = {
req: HttpRequest,
res: HttpResponse,

MODIFY
src/http.listener.ts
src/http.listener.ts
import { Subject, of } from 'rxjs';
import { catchError, defaultIfEmpty, switchMap, tap } from 'rxjs/operators';
-import { Effect, EffectResponse, combineEffects, combineMiddlewareEffects } from './effects';
-import { Http, HttpRequest, HttpResponse } from './http.interface';
-import { getErrorMiddleware } from './middlewares';
-import { handleResponse } from './response';
-import { StatusCode } from './util';
+import { combineEffects, combineMiddlewareEffects } from './effects/effects.combiner';
+import { Effect, EffectResponse } from './effects/effects.interface';
+import { Http, HttpRequest, HttpResponse, HttpStatus } from './http.interface';
+import { getErrorMiddleware } from './middlewares/error.middleware';
+import { handleResponse } from './response/response.handler';
type HttpListenerConfig = {
middlewares: Effect<HttpRequest>[],
@@ -20,7 +20,7 @@ export const httpListener = ({ middlewares, effects, errorMiddleware }: HttpList
combineMiddlewareEffects(middlewares)(res)(req)
.pipe(
switchMap(combineEffects(effects)(res)),
- defaultIfEmpty({ status: StatusCode.NOT_FOUND }),
+ defaultIfEmpty({ status: HttpStatus.NOT_FOUND }),
tap(handleResponse(res)),
catchError(error =>
getErrorMiddleware(errorMiddleware)(of(req), res, error)

MODIFY
src/index.ts
src/index.ts
-export * from './effects';
-export * from './middlewares';
-export * from './operators';
+export * from './effects/effects.interface';
+export * from './middlewares/bodyParser.middleware';
+export * from './middlewares/error.middleware';
+export * from './middlewares/logger.middleware';
+export * from './operators/ofType.operator';
export * from './http.interface';
export * from './http.listener';

MODIFY
src/middlewares/bodyParser.middleware.ts
src/middlewares/bodyParser.middleware.ts
import { Observable, throwError } from 'rxjs';
import { catchError, map, switchMap, tap, toArray } from 'rxjs/operators';
-import { Effect } from '../effects';
-import { HttpRequest } from '../http.interface';
-import { ContentType, StatusCode } from '../util';
+import { Effect } from '../effects/effects.interface';
+import { HttpRequest, HttpStatus } from '../http.interface';
+import { ContentType } from '../util/contentType.util';
import { HttpError } from '../util/error.util';
export const fromReadableStream = (stream: HttpRequest): Observable<any> => {
@@ -50,7 +50,7 @@ export const bodyParser$: Effect<HttpRequest> = (request$, response) => request$
switchMap(getBody),
tap(body => req.body = body),
map(body => req),
- catchError(error => throwError(new HttpError('Request body parse error', StatusCode.BAD_REQUEST)))
+ catchError(error => throwError(new HttpError('Request body parse error', HttpStatus.BAD_REQUEST)))
)
: request$
)

MODIFY
src/middlewares/error.middleware.ts
src/middlewares/error.middleware.ts
import { map } from 'rxjs/operators';
-import { Effect, EffectResponse } from '../effects';
-import { StatusCode } from '../util';
+import { Effect, EffectResponse } from '../effects/effects.interface';
+import { HttpStatus } from '../http.interface';
import { HttpError, isHttpError } from '../util/error.util';
export type Error = HttpError;
@@ -9,11 +9,11 @@ export const getErrorMiddleware = (customError$?: Effect<EffectResponse, Error>)
? customError$
: error$;
-export const getStatusCode = (error: Error): StatusCode => isHttpError(error)
+export const getStatusCode = (error: Error): HttpStatus => isHttpError(error)
? error.status
- : StatusCode.INTERNAL_SERVER_ERROR;
+ : HttpStatus.INTERNAL_SERVER_ERROR;
-export const errorFactory = (message: string, status: StatusCode, data?: any) => ({
+export const errorFactory = (message: string, status: HttpStatus, data?: any) => ({
error: { status, message, data }
});

DELETE
src/middlewares/index.ts
-export * from './bodyParser.middleware';
-export * from './logger.middleware';
-export * from './error.middleware';

DELETE
src/operators/index.ts
-export {};

DELETE
src/response/index.ts
-export * from './response.handler';
-export * from './responseHeaders.factory';

MODIFY
src/response/responseHeaders.factory.ts
src/response/responseHeaders.factory.ts
import { HttpHeaders } from '../http.interface';
-import { ContentType } from '../util';
+import { ContentType } from '../util/contentType.util';
export const DEFAULT_HEADERS = {
'Content-Type': ContentType.APPLICATION_JSON,

MODIFY
src/util/error.util.ts
src/util/error.util.ts
-import { StatusCode } from './statusCode.util';
+import { HttpStatus } from '../http.interface';
export class ExtendableError extends Error {
constructor(
@@ -12,7 +12,7 @@ export class ExtendableError extends Error {
export class HttpError extends ExtendableError {
constructor(
public readonly message: string,
- public readonly status: StatusCode,
+ public readonly status: HttpStatus,
) {
super('HttpError', message);
}

DELETE
src/util/index.ts
-export * from './contentType.util';
-export * from './statusCode.util';

DELETE
src/util/statusCode.util.ts
-export enum StatusCode {
- OK = 200,
- BAD_REQUEST = 400,
- UNAUTHORIZED = 401,
- FORBIDDEN = 403,
- NOT_FOUND = 404,
- FAILED_DEPENDENCY = 424,
- INTERNAL_SERVER_ERROR = 500,
- SERVICE_UNAVAILABLE = 503,
-}

improvement - resolved issue with circular dependency problem