alfred icon indicating copy to clipboard operation
alfred copied to clipboard

Enchant: Class-Based Middlewares and Endpoint callback

Open NathanDraco22 opened this issue 2 years ago • 2 comments

Thanks for this amazing idea! Inspired by this Issue : https://github.com/rknell/alfred/issues/88

With this Mixin we can create class-based middlewares

class _ExampleMiddleware with CallableRequestMixin{
  @override
  FutureOr call(HttpRequest req, HttpResponse res) {
    if (req.headers.value('Authorization') != 'apikey') {
      throw AlfredException(401, {'message': 'authentication failed'});
    }
  }
}

void main() async {
  final app = Alfred();
  app.all('/example/:id/:name', (req, res) {}, middleware: [_ExampleMiddleware()]);

  await app.listen(); //Listening on port 3000
}

and End-Point callback too !

class _RequestController with CallableRequestMixin {
  @override
  FutureOr call(HttpRequest req, HttpResponse res) => "I'm a Class :)";
}

void main() async {
  final app = Alfred();

  app.get('/text', _RequestController());

  await app.listen(6565); //Listening on port 6565
}

NathanDraco22 avatar Jun 19 '22 01:06 NathanDraco22

Hey @NathanDraco22! I don't think this makes any sense, as the call function comes out of the box with every Dart class and does not add any functionality.

And since it is functional without the need for this, I don't know how much sense it makes.

I'm currently using what I've called RouteHandlers, and this is my implementation of them:

import 'dart:async';

import 'package:alfred/alfred.dart';
import 'package:alfredito/src/validators/validators.dart';
import 'package:meta/meta.dart';

part 'controller.dart';
part 'middleware.dart';

/// {@template route_handler}
/// A Route Handler is a class that can be registered as a callback.
/// {@endtemplate}
abstract class RouteHandler<T extends RouteHandler<T>> {
  /// Here you can define all your variables that will be available in the
  /// route handler.
  FutureOr<dynamic> defineVars(HttpRequest req, HttpResponse res) async {}

  /// This is the method that is called when the route is.
  /// It first creates a new instance of the class itself, then proceeds to
  /// call the [defineVars] function so that every variable gets grabbed,
  /// and then executes the [run] function.
  FutureOr<dynamic> call(HttpRequest req, HttpResponse res) async {
    final instance = newInstance;
    // this handles the request
    await instance.defineVars(req, res);
    req.validate();
    await instance.run(req, res);
  }

  /// This is where you should handle all the logic.
  FutureOr<dynamic> run(HttpRequest req, HttpResponse res);

  /// Creates a new instance of this class (used to avoid usage of dart: mirrors)
  T get newInstance;
}

and an example of a controller/middleware:

class ExampleController extends RouteHandler<ExampleController> {
  late String apiKey;

  @override
  FutureOr<void> defineVars(HttpRequest req, HttpResponse res) async {
    // here you can grab and process the variables
    // that come from the request itself, and save them as vars inside the class
    final _apiKey = req.headers.value('Authorization');
    if (_apiKey == null || _apiKey.isEmpty) {
      throw AlfredException(401, {'message': 'authentication failed'});
    }
    apiKey = _apiKey;
  }

  @override
  FutureOr<dynamic> run(HttpRequest req, HttpResponse res) async {
    // here you can do whatever you want functionality-wise
    await res.json(
      <String, String>{
        'message': 'hello world',
        'apiKey': apiKey,
      },
    );
  }

  @override
  ExampleController get newInstance => ExampleController();
}

tomassasovsky avatar Jun 19 '22 01:06 tomassasovsky

Yeah you're right, this Mixin is only like tool or helper, to create a faster function signature. I thought like a Expanded widget in flutter, is only a Flexible with some common settings, This mixin is only like a helper.

NathanDraco22 avatar Jun 19 '22 01:06 NathanDraco22