Search code examples
javascripthttproutermiddlewarekoa

Koa, Node.js, Server - How can I get Koa's Router-level middleware function from the Server object?


I want to get the call to middleware function from the server object that I create last in the code. How can I achieve that? It seems like there is not a lot of information out there. My goal is to extract the middleware functions and keep a index for all the calls. When I test the application, Ido not have to actually call through the http requests.

const app = new Koa();
  const router = new Router();

  async function middleware(context: Koa.Context) {
    // the client is requesting a specific statusCode to be returned
    if (context.query.status !== undefined) {
      context.status = parseInt(context.query.status, 10);
      if (context.query.body !== undefined) {
        try {
          context.body = JSON.parse(context.query.body);
        } catch (e) {
          context.body = context.query.body;
        }
      }
      return;
    }
    // put all the inbound x-headers in the response, prepended with 'ping.'
    Object.keys(context.headers).forEach(header => {
      if (header.toLowerCase().startsWith('x-')) {
        context.response.set(`x-ping-${header.slice(2)}`, context.headers[header]);
      }
    });

    context.body = {
      ping: (context.request as any).body
    };
    context.status = 200;
  }
  router.head('/ping', middleware);
  router.get('/ping', middleware);
  router.del('/ping', middleware);
  router.put('/ping', middleware);
  router.post('/ping', middleware);
  router.patch('/ping', middleware);

  app.use(koaBody());
  app.use(router.routes());
  app.use(router.allowedMethods());

  const port = await findPort();
  const server = app.listen(port);

Here are some logs that might help with this question. console.log(server):

Server {
  domain: null,
  _events: 
   { request: [Function: handleRequest],
     connection: [ [Function: connectionListener], [Function] ] },
  _eventsCount: 2,
  _maxListeners: undefined,
  _connections: 0,
  _handle: 
   TCP {
     reading: false,
     owner: [Circular],
     onread: null,
     onconnection: [Function] },
  _usingWorkers: false,
  _workers: [],
  _unref: false,
  allowHalfOpen: true,
  pauseOnConnect: false,
  httpAllowHalfOpen: false,
  timeout: 120000,
  keepAliveTimeout: 5000,
  _pendingResponseData: 0,
  maxHeadersCount: null,
  _connectionKey: '6::::49612',
  [Symbol(IncomingMessage)]: 
   { [Function: IncomingMessage]
     super_: 
      { [Function: Readable]
        ReadableState: [Function: ReadableState],
        super_: [Function],
        _fromList: [Function: fromList] } },
  [Symbol(ServerResponse)]: { [Function: ServerResponse] super_: { [Function: OutgoingMessage] super_: [Function] } },
  [Symbol(asyncId)]: 3220 }

Solution

  • I figured it out. In order to not use the server when testing the middleware, you need to use app.callback().

    Code Preview:

     const socket: net.Socket = new net.Socket();
     const req = new http.IncomingMessage(socket);
     req.url = url;
     req.method = method;
     req.headers = headers; // (whatever more you need to set)
    
     if (json) {
         (req as any).body = json;
     }
     const res = new http.ServerResponse(req);
     const cb = callback(app);
     try {
         response = (await cb(req, res));
          (...)