deepkit / deepkit-framework

A new full-featured and high-performance TypeScript framework
https://deepkit.io/
MIT License
3.2k stars 123 forks source link

Support the ability to re-use packages from the Express/Connect ecosystem #116

Closed WonderPanda closed 3 years ago

WonderPanda commented 3 years ago

Taken from Discord conversation with @marcj

maybe we should just add support for the middleware API. make it easy to register a middleware for a route path and define its execution point in the http kernel (onAuth, onRequest, etc). the framework then has this information to debug execution of those middleware functions and an user can execute arbitrary plugins that would work in express as well, so that passport.js for example works almost the same with deepkit out of the box

Rush commented 3 years ago

How to use express middlewares today:

const expressMiddleware = async (
  request: HttpRequest, response: HttpResponse,
  middleware: (req: Request, res: Response, next: NextFunction) => void,
) => {
  const req = request as any as Request;
  const res = response as Response;
  return new Promise<void>((resolve, reject) => {
    middleware(req, res, (err: any) => {
      if (err) { return reject(err); }
      resolve();
    });
  });
};

const expressUse = async (
  request: HttpRequest, response: HttpResponse,
  ...middlewares: Array<(req: Request, res: Response, next: NextFunction) => void>
) => {
  for (const middleware of middlewares) {
    await expressMiddleware(request, response, middleware);
  }
  const req = request as any as Request;
  const res = response as Response;
  return { req, res };
};

and then use it as such (in this case with passport)

@injectable()
class AuthenticationListener {
  constructor(private logger: Logger) {
  }

  @eventDispatcher.listen(httpWorkflow.onAuth)
  async onAuth(event: typeof httpWorkflow.onAuth.event) {
    try {
      const { request, response } = event;
      const { req } = await expressUse(request, response,
        cookieParser,
        passport.initialize(),
        passport.authenticate(['jwt'], { session: true}),
      );

      if (req.user) {
        // request.store.user can then be accessed by parameter resolvers or http-scoped injection
        request.store.user = req.user;
      }
      if (event.route.groups.includes('auth') && !req.user) {
        event.accessDenied();
      }
    } catch (err) {
      this.logger.error('Error authenticating request', err);
      event.accessDenied();
    }
  }
}
marcj commented 3 years ago

This has been implemented, docs: https://deepkit.io/documentation/framework/http/middleware