feat(core): route builder POC
MODIFY
packages/@integration/src/effects/user.effects.ts
packages/@integration/src/effects/user.effects.ts
-import { EffectFactory, combineRoutes, HttpError, HttpStatus, use } from '@marblejs/core';
+import { combineRoutes, HttpError, HttpStatus, use, r } from '@marblejs/core';
import { requestValidator$, t } from '@marblejs/middleware-io';
import { throwError, of } from 'rxjs';
import { map, switchMap, catchError, mergeMap } from 'rxjs/operators';
@@ -15,18 +15,18 @@ const postUserValidator$ = requestValidator$({
}),
});
-const getUserList$ = EffectFactory
- .matchPath('/')
- .matchType('GET')
- .use(req$ => req$.pipe(
+const getUserList$ = r.pipe(
+ r.matchPath('/'),
+ r.matchType('GET'),
+ r.useEffect(req$ => req$.pipe(
mergeMap(Dao.getUsers),
map(users => ({ body: users })),
- ));
+ )));
-const getUser$ = EffectFactory
- .matchPath('/:id')
- .matchType('GET')
- .use(req$ => req$.pipe(
+const getUser$ = r.pipe(
+ r.matchPath('/:id'),
+ r.matchType('GET'),
+ r.useEffect(req$ => req$.pipe(
use(getUserValidator$),
mergeMap(req => of(req).pipe(
map(req => req.params.id),
@@ -36,17 +36,17 @@ const getUser$ = EffectFactory
new HttpError('User does not exist', HttpStatus.NOT_FOUND)
))
)),
- ));
+ )));
-const postUser$ = EffectFactory
- .matchPath('/')
- .matchType('POST')
- .use(req$ => req$.pipe(
+const postUser$ = r.pipe(
+ r.matchPath('/'),
+ r.matchType('POST'),
+ r.useEffect(req$ => req$.pipe(
use(postUserValidator$),
map(req => req.body),
mergeMap(Dao.postUser),
map(body => ({ body })),
- ));
+ )));
export const user$ = combineRoutes('/user', {
middlewares: [authorize$],

MODIFY
packages/core/package.json
packages/core/package.json
"chalk": "~2.4.1",
"file-type": "^8.0.0",
"mime": "^2.3.1",
- "path-to-regexp": "^2.4.0"
+ "path-to-regexp": "^2.4.0",
+ "fp-ts": "1.12.2"
},
"devDependencies": {
"@types/file-type": "^5.2.1",

MODIFY
packages/core/src/index.ts
packages/core/src/index.ts
@@ -3,6 +3,7 @@ export { defaultError$ } from './error/error.effect';
export { coreErrorFactory, CoreErrorOptions } from './error/error.factory';
export { HttpError, CoreError, EventError } from './error/error.model';
export { combineRoutes } from './router/router.combiner';
+export { r } from './router/router.builder';
export { combineEffects, combineMiddlewares } from './effects/effects.combiner';
export { createEffectMetadata } from './effects/effectsMetadata.factory';
export * from './effects/effects.interface';

ADD
packages/core/src/router/router.builder.ts
+import { Either, left, right } from 'fp-ts/lib/Either';
+import { HttpMiddlewareEffect, HttpEffect } from '../effects/http-effects.interface';
+import { combineMiddlewares } from '../effects/effects.combiner';
+import { coreErrorFactory } from '../error/error.factory';
+import { HttpMethod } from '../http.interface';
+import { RouteEffect } from './router.interface';
+import { CoreError } from '../error/error.model';
+
+type Pipeable = (route: Either<CoreError, Partial<RouteEffect>>) => Either<CoreError, Partial<RouteEffect>>;
+
+const pipe = (
+ fn1: Pipeable,
+ fn2: Pipeable,
+ fn3: Pipeable,
+ ...fns: Array<Pipeable>
+) => {
+ const initial = right<CoreError, Partial<RouteEffect>>({});
+ const pipeable = [fn1, fn2, fn3, ...fns];
+ const piped = pipeable.reduce(
+ (prevFn, nextFn) => value => nextFn(prevFn(value)),
+ value => value,
+ );
+
+ return piped(initial)
+ .getOrElseL(error => { throw error; }) as RouteEffect;
+};
+
+const matchPath = (path: string): Pipeable => route =>
+ !!path
+ ? route.map(r => ({ ...r, path }))
+ : left(coreErrorFactory('Route path has to be defined', { contextMethod: 'matchPath'}));
+
+const matchType = (method: HttpMethod): Pipeable => route =>
+ !!method
+ ? route.map(r => ({ ...r, method }))
+ : left(coreErrorFactory('HttpMethod has to be defined', { contextMethod: 'matchType'}));
+
+const use = (middleware: HttpMiddlewareEffect): Pipeable => route =>
+ !!middleware
+ ? route.map(r => ({
+ ...r,
+ middleware: r.middleware
+ ? combineMiddlewares(r.middleware, middleware)
+ : combineMiddlewares(middleware)
+ }))
+ : left(coreErrorFactory('Middleware has to be defined', { contextMethod: 'use'}));
+
+const useEffect = (effect: HttpEffect): Pipeable => route =>
+ !!effect
+ ? route.map(r => ({ ...r, effect }))
+ : left(coreErrorFactory('Effect has to be defined', { contextMethod: 'useEffect'}));
+
+export const r = { pipe, matchPath, matchType, useEffect, use };

MODIFY
packages/core/src/router/router.factory.ts
packages/core/src/router/router.factory.ts
@@ -32,8 +32,10 @@ export const factorizeRouting = (
const foundRoute = routing.find(route => route.regExp.source === regExp.source);
const method: RoutingMethod = {
effect: route.effect,
- middleware: middlewares.length > 0
- ? middlewares.length > 1 ? combineMiddlewares(...middlewares) : middlewares[0]
+ middleware: middlewares.length
+ ? route.middleware
+ ? combineMiddlewares(...middlewares, route.middleware)
+ : combineMiddlewares(...middlewares)
: undefined,
parameters,
};

MODIFY
packages/middleware-io/package.json
packages/middleware-io/package.json
"rxjs": "~6.3.3"
},
"dependencies": {
- "io-ts": "~1.5.1"
+ "io-ts": "^1.8.1"
},
"devDependencies": {
"@marblejs/core": "^2.0.0-rc.1"

MODIFY
yarn.lock
yarn.lock
@@ -2306,7 +2306,7 @@ formidable@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659"
-fp-ts@^1.0.0:
+fp-ts@1.12.2, fp-ts@^1.0.0:
version "1.12.2"
resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.12.2.tgz#4297ceb989a81d05df10552fb969a73104293a1f"
integrity sha512-h5+V5g4o4CiOoAdUxx+g+/n3n9MYw8SgjBygEDqyuyq3gmGSsUKvHtSvHstZ2DVVBadP+XqGiQ6V/qYyMK1iKA==
@@ -2839,10 +2839,10 @@ invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
-io-ts@~1.5.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.5.1.tgz#8824f6011ae5987d8bd601af05c4483d013f3044"
- integrity sha512-2VvrD1xESb8vzZ1kz0fy3mYAALkeAfCLhc7JQKGGvgnxfYgimeodvqf2hEeFEf7ITDEhaGg37dRPsmcp9wliHQ==
+io-ts@^1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.8.1.tgz#8e4534e5eb491f0b624394ba42085f68dc84268b"
+ integrity sha512-MhFHaBbzw1MK6s16QPW8Tgkj5SW5wBjeQERsk5hupfBSC6WQeQ4MoPACPbm7LUUXU8jZJaqrVGuBTWqCuZYP0A==
dependencies:
fp-ts "^1.0.0"

feat(core): route builder POC