project-inra / inra-server

A set of modules for Node.js servers suitable for any kind of applications. Provides a higher level of abstraction, syntactic sugar and a lot of utility modules.
https://github.com/project-inra/inra-server/wiki
MIT License
8 stars 1 forks source link

Use decorators/classes instead of handlers #6

Closed Bartozzz closed 6 years ago

Bartozzz commented 6 years ago

Our current system is quite nice when in comes to define default handlers and populate loaded files with initializer's instance:

app.addHandler("Router", function routeHandler(resource) { /* … */ });
app.addHandler("Middleware", function middlewareHandler(resource) { /* … */ });

app.addHandler("default", function defaultHandler(resource) {
  resource(app);
});

It has a few limitations:

  1. Imported class and functions' names must respect a given naming convention. Right now, handlers can recognize imported files based on their suffixes only.

  2. Sometimes, the default handler is not enough. E.g. it cannot handle both classes and functions, so we need two separate handlers for each case. In order to define a new resource type, we must define it's own handler directly in the bootstrap section.

  3. Some (native) handlers use and modify app internals. Those handlers should not be overridden by any user-defined handler – right now it is possible by simply passing another function to .addHandler.

  4. This is kinda an anti-pattern. Each file should be as much independent from the rest of the application as possible. Right now, each class in strongly coupled with inra-project-server and there's no easy way to migrate to another framework because of how handlers are implemented.

Proposal 1: decorators

@controller("/foo", …)
class FooRouter {
  @get("/", …)
  async read(ctx, next) {
    // …
  }
}

In this case @controller is a simple function which, once loaded, handles FooRouter and populates it with app.

Pros:

Cons:

Proposal 2: extending

This is a standard solution in languages such as PHP where there's no decorators.

class FooRouter extends Controller {
  @get("/", …)
  async read(ctx, next) {
    // …
  }
}

Pros:

Cons: