GoogleCloudPlatform / functions-framework-dart

FaaS (Function as a service) framework for writing portable Dart functions
https://pub.dev/packages/functions_framework
Apache License 2.0
535 stars 54 forks source link

Add Support for Middleware #250

Closed mtwichel closed 3 years ago

mtwichel commented 3 years ago

Motivation

As discussed in #222 and #240, It would be nice to support middleware in your Dart functions for tasks like CORS support or authentication. This approach takes inspriation from the approach documented with Firebase Cloud Functions as well as the existing method of using annotations in the Dart Functions Framework. The approach taken here should also make it very easy to use existing middleware written for shelf as it uses the same signatures for middleware methods.

This change is not breaking!

New Usage

You can declare a middleware function like so:

@CloudFunctionMiddleware()
Handler middleware(Handler handler) {
    // Function goes here
}

This will then be injected into the shelf pipeline and run before your actual function code is called.

This function essentially wraps the existing handler function in your middleware function. The handler parameter is that existing handler function.

As a silly example, here’s a function that returns “POST Not Allowed” to any request that uses the POST method, otherwise it returns the underlying function:

@CloudFunctionMiddleware()
Handler middleware(Handler innerHandler) => (req) {
      if (req.method == 'POST') {
        return Response.ok('POST Not Allowed');
      } else {
        return innerHandler(req);
      }
    };

Technical Details

The PR changes the serve method to accept a list of Middlewares, which are your middleware functions taged with @CloudFunctionMiddleware. These are then passed into the run method which adds them to the shelf Pipeline.

During the build step, your functions are identified and added to the serve method in the generated bin/server.dart. For this, the PR creates new target called a MiddlewareTarget which represents the middleware. Since only one method signature is supported, it has one concrete constructor.

Hope you enjoy :)

mtwichel commented 3 years ago

Thanks @subfuzion for the feedback! I'll take a look at these issues tonight. Especially thanks for the tip on the tests - I wasn't exactly sure where to slot them in.

kevmoo commented 3 years ago

I'm not convinced this is worth the added complexity. It's easy to create a stack of middleware and add it to a function. Having many functions in a project is supported, but I don't think it'd be super common.

tobytraylor commented 1 year ago

@kevmoo How do you add a pipeline of middleware to one of the cloud functions. I can't quite figure it out.

jimmyff commented 1 year ago

kevmoo How do you add a pipeline of middleware to one of the cloud functions. I can't quite figure it out.

@tobytraylor : Example here: https://github.com/GoogleCloudPlatform/functions-framework-dart/issues/222#issuecomment-1293372664