docs: function buildRoute (ravelInstance, routes, koaRouter, methodName, meta) {
    const basePath = Metadata.getClassMetaValue(routes, '@role', 'name');
    const fullPath = upath.toUnix(upath.posix.join(basePath, meta.path));
  
    let verb;
    switch (meta.verb) {
      case PUT:
        verb = 'put';
        break;
      case POST:
        verb = 'post';
        break;
      case PATCH:
        verb = 'patch';
        break;
      case DELETE:
        verb = 'delete';
        break;
      default:
        verb = 'get';
    }
  
    if (!meta.suppressLog) {
      ravelInstance.$log.info(`Registering endpoint ${verb} ${fullPath}`);
    }
  
    let args = [fullPath];
  
    // build middleware from metadata
    const middleware = [];
  
    // apply class-level @authenticated middleware, if present
    // we only need to check for method-level @authenticated if it isn't on the class
    if (Metadata.getClassMeta(routes, '@authenticated')) {
      const config = Metadata.getClassMetaValue(routes, '@authenticated', 'config', {});
      middleware.push(
        new AuthenticationMiddleware(ravelInstance, config.redirect, config.allowRegistration).middleware());
    } else if (Metadata.getMethodMeta(routes, methodName, '@authenticated')) {
      const config = Metadata.getMethodMetaValue(routes, methodName, '@authenticated', 'config', {});
      middleware.push(
        new AuthenticationMiddleware(ravelInstance, config.redirect, config.allowRegistration).middleware());
    }
  
    // apply respond middleware automatically
    middleware.push(rest.respond());
  
    // apply class-level and method-level @transaction middleware, if present (in the correct order)
    let dbProviders;
    if (Metadata.getClassMeta(routes, '@transaction')) {
      dbProviders = Metadata.getClassMetaValue(routes, '@transaction', 'providers', []);
    }
    if (Metadata.getMethodMeta(routes, methodName, '@transaction')) {
      dbProviders = dbProviders || [];
      dbProviders = dbProviders.concat(Metadata.getMethodMetaValue(routes, methodName, '@transaction', 'providers', []));
    }
    if (dbProviders !== undefined) {
      middleware.push(ravelInstance.$db.middleware(...dbProviders));
    }
  
    // apply class-level @before middleware, if any
    let toInject = [].concat(Metadata.getClassMetaValue(routes, '@before', 'middleware', []));
  
    // then method-level @before middleware, if any
    toInject = toInject.concat(Metadata.getMethodMetaValue(routes, methodName, '@before', 'middleware', []));
  
    for (let i = 0; i < toInject.length; i++) {
      const m = toInject[i];
      middleware.push(ravelInstance[symbols.injector].getModule(routes, m));
    }
  
    // then cache middleware, if present
    // method-level @cache overrides class-level cache
    if (Metadata.getMethodMeta(routes, methodName, '@cache')) {
      const config = Metadata.getMethodMetaValue(routes, methodName, '@cache', 'options', {});
      middleware.push(
        new ResponseCacheMiddleware(ravelInstance).middleware(config));
    } else if (Metadata.getClassMeta(routes, '@cache')) {
      const config = Metadata.getClassMetaValue(routes, '@cache', 'options', {});
      middleware.push(
        new ResponseCacheMiddleware(ravelInstance).middleware(config));
    }
  
    // finally push actual function handler, but wrap it with a generator
    if (meta.endpoint) {
      middleware.push(async function (ctx, next) {
        const result = meta.endpoint.bind(routes)(ctx);
        // if handler returns a Promise, await on it
        if (result && result instanceof Promise) {
          await result;
        }
        // then await next middleware
        await next();
      });
    } else {
      // if there's no handler, this @mapping represents an endpoint which just returns a status code
      middleware.push(async (ctx) => {
        ctx.respondOptions = {okCode: meta.status};
      });
    }
  
    args = args.concat(middleware);
    // now call underlying koa method to register middleware at specific route
    koaRouter[verb](...args);
  }