added functionality: breaks the middleware chain when next() method not called

This commit is contained in:
Camel Aissani 2016-06-30 23:35:20 +02:00
parent 1655e52436
commit f60e7f825c
5 changed files with 178 additions and 65 deletions

View File

@ -64,53 +64,84 @@ export default class Application {
///////////////////////////////////////////////////////
// Ajax request
_fetch({method, uri, headers, data}, resolve, reject) {
if (this.lastVisited) {
for (const router of this.routers) {
const routes = router.getRoutes(this.lastVisited.uri, this.lastVisited.method);
for (const route of routes) {
if (route.middleware.exited) {
route.middleware.exited(this.lastVisited);
}
// calls middleware exited method
for (const router of this.routers) {
const routes = router.visited();
for (const route of routes) {
if (route.middleware.exited) {
route.middleware.exited(route.visited);
route.visited = null;
}
}
}
// gathers all routes impacted by the uri
const currentRoutes = [];
for (const router of this.routers) {
const routes = router.getRoutes(uri, method);
const routes = router.routes(uri, method);
currentRoutes.push(...routes);
}
// calls middleware entered method
for (const route of currentRoutes) {
if (route.middleware.entered) {
route.middleware.entered({method, uri, headers, data});
}
if (route.middleware.next && !route.middleware.next()) {
break;
}
}
this.requester.fetch({uri, method}, (request, response) => {
this.lastVisited = {method, uri, headers, data};
for (const route of currentRoutes) {
if (route.middleware.updated) {
route.middleware.updated(request, response);
} else {
route.middleware(request, response);
// invokes http request
this.requester.fetch({uri, method},
(request, response) => {
for (const route of currentRoutes) {
route.visited = {method, uri, headers, data};
// calls middleware updated method
if (route.middleware.updated) {
route.middleware.updated(request, response);
if (route.middleware.next && !route.middleware.next()) {
break;
}
} else {
// calls middleware method
let breakMiddlewareLoop = true;
const next = () => {
breakMiddlewareLoop = false;
}
route.middleware(request, response, next);
if (breakMiddlewareLoop) {
break;
}
}
}
}
if (resolve) {
resolve(request, response);
}
}, (request, response) => {
for (const route of currentRoutes) {
if (route.middleware.failed) {
route.middleware.failed(request, response);
} else {
route.middleware(request, response);
if (resolve) {
resolve(request, response);
}
},
(request, response) => {
for (const route of currentRoutes) {
// calls middleware failed method
if (route.middleware.failed) {
route.middleware.failed(request, response);
if (route.middleware.next && !route.middleware.next()) {
break;
}
} else {
// calls middleware method
let breakMiddlewareLoop = true;
const next = () => {
breakMiddlewareLoop = false;
}
route.middleware(request, response, next);
if (breakMiddlewareLoop) {
break;
}
}
}
if (reject) {
reject(request, response);
}
}
if (reject) {
reject(request, response);
}
});
}
}

View File

@ -16,4 +16,8 @@ export default class Middleware {
failed(request, response) {
}
next() {
return true;
}
}

View File

@ -7,6 +7,7 @@ class Route {
this.uriPart = uriPart;
this.method = method;
this.middleware = middleware;
this.visited = false;
}
get uri() {
@ -35,16 +36,16 @@ export default class Router {
if (baseUri) {
this.baseUri = baseUri;
}
this.routes = [];
this._routes = [];
}
_add(route) {
this.routes.push(route);
this._routes.push(route);
return this;
}
getRoutes(uri, method) {
return this.routes.filter((route) => {
routes(uri, method) {
return this._routes.filter((route) => {
if (route.method !== method) {
return false;
}
@ -60,6 +61,12 @@ export default class Router {
});
}
visited() {
return this._routes.filter((route) => {
return route.visited;
});
}
all(...args) {
if (args.length === 0) {
throw new TypeError(`use all method takes at least a middleware`);

View File

@ -76,7 +76,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.use((request, response) => {spy()});
app.use((request, response, next) => {spy()});
app.httpGet('/', (request, response) => {
assert(spy.callCount === 1);
@ -93,7 +93,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.use('/route1', (request, response) => {spy()});
app.use('/route1', (request, response, next) => {spy()});
app.httpGet('/route1', (request, response) => {
assert(spy.callCount === 1);
@ -118,7 +118,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.use((request, response) => {spy()});
app.use((request, response, next) => {spy()});
app.httpGet('/', null, (request, response) => {
assert(spy.callCount === 1);
@ -190,8 +190,8 @@ describe('Application', () => {
const spy = sinon.spy();
const router = new frontexpress.Router();
router
.get((request, response) => {spy()})
.post((request, response) => {spy()});
.get((request, response, next) => {spy()})
.post((request, response, next) => {spy()});
const app = frontexpress();
app.set('http-requester', requester);
@ -211,8 +211,8 @@ describe('Application', () => {
const spy = sinon.spy();
const router = new frontexpress.Router();
router
.get((request, response) => {spy()})
.post((request, response) => {spy()});
.get((request, response, next) => {spy()})
.post((request, response, next) => {spy()});
const app = frontexpress();
app.set('http-requester', requester);
@ -292,7 +292,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.get((request, response) => {spy()});
app.get((request, respons, next) => {spy()});
app.httpGet('/', (request, response) => {
assert(spy.callCount === 1);
@ -309,7 +309,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.get('/route1', (request, response) => {spy()});
app.get('/route1', (request, response, next) => {spy()});
app.httpGet('/route1', (request, response) => {
assert(spy.callCount === 1);
@ -374,7 +374,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.route().get((request, response) => {spy()});
app.route().get((request, response, next) => {spy()});
app.httpGet('/', (request, response) => {
assert(spy.calledOnce);
@ -391,7 +391,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.route('/').get((request, response) => {spy()});
app.route('/').get((request, response, next) => {spy()});
app.httpGet('/', (request, response) => {
assert(spy.calledOnce);
@ -408,7 +408,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.route('/route1').get((request, response) => {spy()});
app.route('/route1').get((request, response, next) => {spy()});
app.httpGet('/route1', (request, response) => {
assert(spy.calledOnce);
@ -425,7 +425,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.route().get('/subroute1', (request, response) => {spy()});
app.route().get('/subroute1', (request, response, next) => {spy()});
app.httpGet('/subroute1', (request, response) => {
assert(spy.calledOnce);
@ -441,7 +441,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.route('/').get('/subroute1', (request, response) => {spy()});
app.route('/').get('/subroute1', (request, response, next) => {spy()});
app.httpGet('/subroute1', (request, response) => {
assert(spy.calledOnce);
@ -457,7 +457,7 @@ describe('Application', () => {
const app = frontexpress();
app.set('http-requester', requester);
app.route('/route1').get('/subroute1', (request, response) => {spy()});
app.route('/route1').get('/subroute1', (request, response, next) => {spy()});
app.httpGet('/route1/subroute1', (request, response) => {
assert(spy.calledOnce);
@ -488,6 +488,7 @@ describe('Application', () => {
const spy_get_entered = sinon.spy(getMiddleware, 'entered');
const spy_get_updated = sinon.spy(getMiddleware, 'updated');
const spy_get_exited = sinon.spy(getMiddleware, 'exited');
const spy_get_next = sinon.spy(getMiddleware, 'next');
app.route('/route1').get(getMiddleware);
@ -495,8 +496,11 @@ describe('Application', () => {
assert(spy_get_entered.callCount === 1);
assert(spy_get_updated.callCount === 1);
assert(spy_get_exited.callCount === 0);
assert(spy_get_next.callCount === 2);
assert(spy_get_entered.calledBefore(spy_get_updated));
assert(spy_get_next.calledAfter(spy_get_entered));
assert(spy_get_next.calledAfter(spy_get_updated));
done();
},
(request, response) => {
@ -605,5 +609,60 @@ describe('Application', () => {
done();
});
});
it('next method', (done) => {
const app = frontexpress();
app.set('http-requester', requester);
const m1 = new frontexpress.Middleware('m1');
const m2 = new frontexpress.Middleware('m2');
m2.next = () => false;
const m3 = new frontexpress.Middleware('m3');
const spy_m1 = sinon.spy(m1, 'updated');
const spy_m2 = sinon.spy(m2, 'updated');
const spy_m3 = sinon.spy(m3, 'updated');
app.route('/route1').get(m1).get(m2).get(m3);
app.httpGet('/route1', (request, response) => {
assert(spy_m1.calledOnce);
assert(spy_m2.calledOnce);
assert(spy_m3.callCount === 0);
done();
});
});
});
describe('middleware as function', () => {
beforeEach(()=>{
requester = new Requester();
sinon.stub(requester, 'fetch', ({uri, method, headers, data}, resolve, reject) => {
resolve(
{uri, method, headers, data},
{status: 200, statusText: 'OK', responseText:''}
);
});
});
it('next method', (done) => {
const app = frontexpress();
app.set('http-requester', requester);
const m1 = (req, res, next) => {next()};
const m2 = (req, res, next) => {};
const m3 = (req, res, next) => {next()};
const spy_m1 = sinon.spy(m1);
const spy_m2 = sinon.spy(m2);
const spy_m3 = sinon.spy(m3);
app.route('/route1').get(spy_m1).get(spy_m2).get(spy_m3);
app.httpGet('/route1', (request, response) => {
assert(spy_m1.calledOnce);
assert(spy_m2.calledOnce);
assert(spy_m3.callCount === 0);
done();
});
});
});
});

View File

@ -16,14 +16,26 @@ describe('Router', () => {
});
});
describe('getRoutes method', () => {
describe('visited method', () => {
it('get visited route', ()=> {
const router = new frontexpress.Router();
const middleware = (request, response) => {};
router.get(middleware);
const r1 = router.visited();
assert(r1.length === 0);
});
});
describe('routes method', () => {
it('no root path and no path uri', ()=> {
const router = new frontexpress.Router();
const middleware = (request, response) => {};
router.get(middleware);
const r1 = router.getRoutes('/', 'GET');
const r1 = router.routes('/', 'GET');
assert(r1.length === 1);
assert(r1[0].uri === undefined);
assert(r1[0].method === 'GET');
@ -41,37 +53,37 @@ describe('Router', () => {
.post('/route2', middleware2)
.all('/route3', middleware3);
const r1 = router.getRoutes('/route1', 'GET');
const r1 = router.routes('/route1', 'GET');
assert(r1.length === 1);
assert(r1[0].uri === '/route1');
assert(r1[0].method === 'GET');
assert(r1[0].middleware === middleware1);
const r2 = router.getRoutes('/route2', 'POST');
const r2 = router.routes('/route2', 'POST');
assert(r2.length === 1);
assert(r2[0].uri === '/route2');
assert(r2[0].method === 'POST');
assert(r2[0].middleware === middleware2);
let r3 = router.getRoutes('/route3', 'GET');
let r3 = router.routes('/route3', 'GET');
assert(r3.length === 1);
assert(r3[0].uri === '/route3');
assert(r3[0].method === 'GET');
assert(r3[0].middleware === middleware3);
r3 = router.getRoutes('/route3', 'POST');
r3 = router.routes('/route3', 'POST');
assert(r3.length === 1);
assert(r3[0].uri === '/route3');
assert(r3[0].method === 'POST');
assert(r3[0].middleware === middleware3);
r3 = router.getRoutes('/route3', 'PUT');
r3 = router.routes('/route3', 'PUT');
assert(r3.length === 1);
assert(r3[0].uri === '/route3');
assert(r3[0].method === 'PUT');
assert(r3[0].middleware === middleware3);
r3 = router.getRoutes('/route3', 'DELETE');
r3 = router.routes('/route3', 'DELETE');
assert(r3.length === 1);
assert(r3[0].uri === '/route3');
assert(r3[0].method === 'DELETE');
@ -84,7 +96,7 @@ describe('Router', () => {
router.get(/^\/route1/, middleware);
const r = router.getRoutes('/route1', 'GET');
const r = router.routes('/route1', 'GET');
assert(r.length === 1);
assert(r[0].uri instanceof RegExp);
assert(r[0].uri.toString() === new RegExp('^\/route1').toString());
@ -97,7 +109,7 @@ describe('Router', () => {
router.get('/subroute', new frontexpress.Middleware());
const r = router.getRoutes('/route1/subroute', 'GET');
const r = router.routes('/route1/subroute', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1/subroute');
});
@ -107,7 +119,7 @@ describe('Router', () => {
router.get(new frontexpress.Middleware());
const r = router.getRoutes('/route1', 'GET');
const r = router.routes('/route1', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1');
});
@ -117,7 +129,7 @@ describe('Router', () => {
router.get('/subroute', new frontexpress.Middleware());
const r = router.getRoutes('/route1/subroute', 'GET');
const r = router.routes('/route1/subroute', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1/subroute');
});
@ -127,7 +139,7 @@ describe('Router', () => {
router.get('/subroute ', new frontexpress.Middleware());
let r = router.getRoutes('/route1/subroute', 'GET');
let r = router.routes('/route1/subroute', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1/subroute');
@ -137,7 +149,7 @@ describe('Router', () => {
router.get(new frontexpress.Middleware());
r = router.getRoutes('/route1', 'GET');
r = router.routes('/route1', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1');
});
@ -232,7 +244,7 @@ describe('Router', () => {
router.get(middleware);
const r1 = router.getRoutes('/', 'GET');
const r1 = router.routes('/', 'GET');
assert(r1.length === 1);
assert(r1[0].uri === '/');
assert(r1[0].method === 'GET');
@ -245,7 +257,7 @@ describe('Router', () => {
router.get('/route1', middleware);
const r1 = router.getRoutes('/route1', 'GET');
const r1 = router.routes('/route1', 'GET');
assert(r1.length === 1);
assert(r1[0].uri === '/route1');
assert(r1[0].method === 'GET');