← Усі задачіNode.js · Middle

Ланцюжок middleware як у Koa

Напишіть compose(middlewares): він повертає функцію (ctx) => Promise, що запускає middleware по черзі. Кожне отримує ctx і next; await next() передає керування наступному й чекає, доки решта ланцюжка завершиться, а код після нього виконується на зворотному шляху («цибулина»).

Якщо middleware не викликав next(), решта не виконується. Помилка в будь-якому middleware (синхронна чи асинхронна) відхиляє проміс і її можна перехопити try/catch навколо await next() вище за ланцюжком. Повторний виклик next() в одному middleware - помилка next() called multiple times.

Тести (6)

  1. 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']);
  2. 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');
  3. 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);
  4. 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' });
  5. const app = compose([async (ctx, next) => { await next(); await next(); }]);
    await expect(app({})).rejects.toThrow('next() called multiple times');
  6. const app = compose([(ctx, next) => { throw new Error('sync boom'); }]);
    await expect(app({})).rejects.toThrow('sync boom');
    await compose([])({});