Eine Middleware-Kette im Stil von Koa
Schreib compose(middlewares): es liefert eine Funktion (ctx) => Promise, die die Middlewares der Reihe nach ausführt. Jede bekommt ctx und next; await next() gibt die Kontrolle an die nächste ab und wartet, bis der Rest der Kette fertig ist, und der Code danach läuft auf dem Rückweg (die „Zwiebel“).
Ruft eine Middleware next() nicht auf, läuft der Rest nicht. Ein Fehler in einer beliebigen Middleware (synchron oder asynchron) lehnt das Promise ab und lässt sich weiter oben in der Kette mit try/catch um await next() abfangen. next() zweimal in einer Middleware aufzurufen ist ein Fehler: next() called multiple times.
Strg+Enter führt die Tests aus. Tab rückt ein; um den Editor per Tastatur zu verlassen, drücke Esc und dann Tab. Der Code wird in diesem Browser gespeichert.
Tests (6)
const log = []; const app = compose([ async (ctx, next) => { log.push('a1'); await next(); log.push('a2'); }, async (ctx, next) => { log.push('b1'); await next(); log.push('b2'); }, async () => { log.push('c'); }, ]); await app({}); expect(log).toEqual(['a1', 'b1', 'c', 'b2', 'a2']);
const app = compose([ async (ctx, next) => { ctx.user = 'ann'; await next(); }, async (ctx) => { ctx.body = 'hello ' + ctx.user; }, ]); const ctx = {}; await app(ctx); expect(ctx.body).toBe('hello ann');
const third = fn(); const app = compose([ async (ctx, next) => { ctx.status = 401; }, async () => third(), ]); const ctx = {}; await app(ctx); expect(ctx.status).toBe(401); expect(third).toHaveBeenCalledTimes(0);
const app = compose([ async (ctx, next) => { try { await next(); } catch (e) { ctx.status = 500; ctx.error = e.message; } }, async () => { throw new Error('db down'); }, ]); const ctx = {}; await app(ctx); expect(ctx).toEqual({ status: 500, error: 'db down' });
const app = compose([async (ctx, next) => { await next(); await next(); }]); await expect(app({})).rejects.toThrow('next() called multiple times');
const app = compose([(ctx, next) => { throw new Error('sync boom'); }]); await expect(app({})).rejects.toThrow('sync boom'); await compose([])({});