1

I'm struggling with the following scenario using Deno with Oak. Most tutorials use export const xy = () => {} syntax, when they separate controllers and routes.

In the route then they commonly have something like router.get("/the-route", xy), which is fine, but has several caveats that I want to avoid.

What I don't want

Look at this example:

const someController = async ({
  request,
  response,
}: {
  request: any;
  response: any;
}) => {
  // do something
}

1.) request and response are explicitly "any", which I try to avoid since there is no typesafty and no code-completion availabe. 2.) I want to do this in a class-syntax with an extendable base-controller from which other classes are derived.

What I messed up

So currently I ended up with something like this (which is pretty senseless):

import type { RouterContext } from "https://deno.land/x/oak@v8.0.0/mod.ts";

export class BaseController {
  // deno-lint-ignore no-explicit-any
  protected ctx: RouterContext<{ id: string }, Record<string, any>>;

  // deno-lint-ignore no-explicit-any
  constructor(ctx: RouterContext<{ id: string }, Record<string, any>>) {
    this.ctx = this.getContext(ctx);
  }

  // deno-lint-ignore no-explicit-any
  getContext = (ctx: RouterContext<{ id: string }, Record<string, any>>) => {
    return ctx;
  };
}

As you can see this does pretty much nothing but receiving some context passed down to the controller, which doesn't make any sense, since

  1. I need to do something like router.get("/", (ctx) => { SomeController.createSomething(ctx) }) in my routes.
  2. I need to pass the context everywhere (which clearly is not the goal). If I extended a class with BaseController that has a constructor on it's own I even need to pass the context here with super(ctx : UltraLongType<ThatIDontWantHere>)

What I really want to achieve

Long story short: What I really want to do is to have BaseController.getContext really GET the current context without passing it everywhere.

I unfortunately can't find some helper or injector or whatever service to receive the current RouterContext from "outside".

And I really don't get my head wrapped around this.

Maybe someone can help me with this :)

Thanks in advance and best regards :)

bquarta
  • 559
  • 6
  • 19
  • 1
    "...but has several caveats that I want to avoid." Maybe it would help potential answerers if you'd explain your actual objections to the provided API: what do you want to accomplish that you can't with what's there? – jsejcksn Jul 25 '21 at 02:46
  • What I want to achieve is a simply extendible stucture of class-syntax-controllers, so that "creating a new controller" is just like "class NewController extends BaseController { }" and you're all set and you can start without caring about where to get the Context from and so on... since the BaseController-Class takes care of everything that needs to be wired up. I'm planning to do an API with loads of endpoints and I want those things to stay maintainable. – bquarta Jul 25 '21 at 10:37
  • Maybe my approach is comparable with the way symfony handles the MVC-Pattern in PHP. You have a router.js where you define your routes and tell the Route "hey, here is the controller for it". And there is the Controller that has a base Class that has a method implemented that just says "give me the context, that I will process and return". Hopefully that makes clear my intention :) – bquarta Jul 25 '21 at 11:59
  • 1
    Not sure if this will help but based on your requirements maybe a framework like [Mandarine](https://github.com/mandarineorg/mandarinets) would be of interest? It's build on top of Oak but uses a more class-like syntax with decorators – Zwiers Aug 15 '21 at 10:33
  • Thanks for that hint. Actually I ended up giving Drash a try, which also has a completely different approach and isn't too mature. But so far it is looking good for me. – bquarta Aug 16 '21 at 11:32

0 Answers0