VeryGoodOpenSource / dart_frog

A fast, minimalistic backend framework for Dart 🎯
https://dartfrog.vgv.dev
MIT License
1.85k stars 147 forks source link

feat: middleware for individual routes inside a routes directory. #530

Open manas-maji opened 1 year ago

manas-maji commented 1 year ago

I think middleware for individual routes should be there. Let me explain the problem in details.

Lets assume I want to create two routes for registration.

  1. /register
  2. /register/verify-mobile

So I can create a directory "register" inside "routes" directory and create two files as shown below.

image

Now if I need to use two separate middleware for those two routes I can't do because one middleware per directory is allowed.

I know there is workaround e.g. by extracting request Uri path and using switch or if/else but I feel those are error prone.

Looking forward to this feature along with #467.

Lastly many many thanks for the amazing framework. Flutter & Server with Dart, it's really cool.

felangel commented 1 year ago

Hi @manas-maji 👋 Thanks for opening an issue!

Now if I need to use two separate middleware for those two routes I can't do because one middleware per directory is allowed.

I know there is workaround e.g. by extracting request Uri path and using switch or if/else but I feel those are error prone.

Can you elaborate a bit regarding why do you feel the alternative is error prone? #467 is already possible via a custom entrypoint so you can currently avoid using file-based routing entirely if you'd like without any changes to Dart Frog. Let me know if that helps 👍

manas-maji commented 1 year ago

Hello @felangel Thanks for your response.

By error prone I mean it's little bit messy to write bunch of if/else in one middleware, also a bit hard to manage when no of routes under a sub directory increases.

It will be nice if we can apply middleware per route basis like express.js

For #467 I don't know yet how to configure middleware per route, may be some documentation will surely help. Waiting for documentation for #467 .

garysm commented 1 year ago

@manas-maji If I understand correctly, the custom entry point provides you with the default file based routes. As @felangel mentioned in #467, you can:

...ignore the generated handler (from the file based routes) and build your own handler from one or more routers.

So in that custom entry point, you could pass in your own custom router with different middleware per route(s).

Example:

final myRouter = Router();

myRouter.get('/hello', (Request request) {
  return Response.ok('hello-world');
});

myRouter.get('/user/<user>', (Request request, String user) {
  return Response.ok('hello $user');
});

final myPipeline = Pipeline().addMiddleware(myMiddleware).addHandler(myRouter);
final myHandler = Cascade().add(myPipeline).handler;

return serve(myHandler, ip, port);

You could take a look in the generated .dart_frog/server.dart file to see how the default file-based router is put together.

manas-maji commented 1 year ago

@garysm Thanks for your response.

But it does not meet my requirements. I'm looking for an option to inject middleware for each separate route, also for each HTTP verb, just like we do in express.js.

garysm commented 1 year ago

@garysm Thanks for your response.

But it does not meet my requirements. I'm looking for an option to inject middleware for each separate route, also for each HTTP verb, just like we do in express.js.

For your requirements, you should be able to go off of the example I provided to provide separate middleware for each route and verb:

final getRouter = Router();
final postRouter = Router();
getRouter.get(r'/', rootResponse);
getRouter.get(r'/users', usersResponse);
postRouter.post(r'/users', createUserResponse);
postRouter.post(r'/users/login', loginResponse);
final getPipeline = Pipeline().addMiddleware(_getMiddleware).addHandler(getRouter);
final postPipeline = Pipeline().addMiddleware(_postMiddleware).addHandler(postRouter);
final handler = Cascade().add(getPipeline).add(postPipeline).handler;

You can get as specific as you need if you do want to inject middleware for each separate route.

Hope this helps!

manas-maji commented 1 year ago
final getRouter = Router();
final postRouter = Router();
getRouter.get(r'/', rootResponse);
getRouter.get(r'/users', usersResponse);
postRouter.post(r'/users', createUserResponse);
postRouter.post(r'/users/login', loginResponse);
final getPipeline = Pipeline().addMiddleware(_getMiddleware).addHandler(getRouter);
final postPipeline = Pipeline().addMiddleware(_postMiddleware).addHandler(postRouter);
final handler = Cascade().add(getPipeline).add(postPipeline).handler;

Let's assume I need to add a middleware for POST: '/users/login' route only, into the existing code you have shown. Can you tell me how can I do that?