GithubHelp home page GithubHelp logo

[feat] Objects as middleware about koa HOT 6 OPEN

evert avatar evert commented on April 27, 2024
[feat] Objects as middleware

from koa.

Comments (6)

siakc avatar siakc commented on April 27, 2024

Why no just passing the desired method from a class?

from koa.

evert avatar evert commented on April 27, 2024

This feature request is for increasing ergonomics/ DX. Especially when dealing with routes there's a fair amount of repetition.

Of course helper functions are possible or as you say just work around this, but I asked because it will result in more elegant code.

from koa.

siakc avatar siakc commented on April 27, 2024

Can you provide a reference for this pattern you suggest? My understanding is semantically it makes no difference: there is a method which koa would call. But instead of providing that method directly you suggest we give an object and koa will look for that special method by itself. Now I can't see how this would make the code nicer or more developer friendly.

from koa.

evert avatar evert commented on April 27, 2024

A specific example is that I want users to be able to build controllers as such:

class MyController extends ResourceController {

  get(ctx: Context) {
      /* ... */
  }
}

And I would like users to be able to add this controller using this form:

app.use(new MyController())

My feature request would allow me to define the ResourceController baseclass in a way that Koa can pick this up. Not having this feature requires me to either ask users to call something like:

app.use((new MyController())->mw())

Or add a helper function

app.use(mw(MyController))

Because this has to be done for each route/controller, this is kind of an annoying overhead. I went the helper function route for this, below is the full reference of my ResourceController. But having built-in support for this would be nicer.

import { METHODS } from 'node:http';
import { Context, Middleware } from 'koa';
import { MethodNotAllowed, NotImplemented } from '@curveball/http-errors';

/**
 * Takes a ResourceController subclass, instantiates it and returns
 * a koa-compatible middleware.
 */
export function mw(cl: typeof ResourceController): Middleware {

  const controller = new cl();
  return controller.dispatch.bind(controller);

}

/**
 * The ResourceController is a base class for controllers that
 * maps HTTP methods like GET, PUT to class methods like 'get', 'put'.
 */
export class ResourceController {

  constructor() {

    // HEAD fallback. It could be desirable to reimplement HEAD faster, but this is an OK default and just as slow as GET but with fewer bytes sent.
    if ('get' in this && !('head' in this)) {
      (this as any).head = this.get;
    }

  }

  options(ctx: Context) {

    ctx.body = '';
    ctx.set(
      'Allow',
      METHODS.filter(method => method.toLowerCase() in this).join(',')
    );

  }

  dispatch(ctx: Context): void|Promise<void> {

    if (!METHODS.includes(ctx.method)) {
      throw new NotImplemented(`HTTP method not implmented ${ctx.method}`);
    }

    const classMethod = ctx.method.toLowerCase();
    if (typeof (this as any)[classMethod] === 'function') {
      return (this as any)[classMethod](ctx);
    } else {
      throw new MethodNotAllowed(`The ${ctx.method} method is not supported at this endpoint`);
    }

  }

}

from koa.

siakc avatar siakc commented on April 27, 2024

Well I would have done it like this:
A global middleware factory:

function ControllerObj(c, ...params) {
  const controllerInstance = new c(...params)

  return function mw(ctx, next) {
    const method = ctx.method.toLowerCase()
    if(typeof controllerInstance[method] !== 'function') {
      ctx.throw(405)
    }
    controllerInstance[method](ctx, next)
  }
}

A controller class:

class ControllerX {
  constructor(aKnob) {
    this.aKnob = aKnob  // Some tweaks for this route 
  }
  async get(ctx, next) {
    ctx.status = 200
    ctx.body = this.aKnob
    await next()
  }
  // more methods here...
}

And finally:

app
  .use(ControllerObj(ControllerX, 'desiredResponse'))

My belief is that this is not such a general pattern to be implemented in Koa. A plugin maybe...

from koa.

evert avatar evert commented on April 27, 2024

Sure, let's see what the maintainers say. Your approach doesn't really make a difference in terms of cognitive overhead.

from koa.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.