cors-middleware icon indicating copy to clipboard operation
cors-middleware copied to clipboard

Provide an example for dynamically specifying allowed methods for Slim 4

Open jk opened this issue 4 years ago • 4 comments

I've trouble dynamically specifying the allowed methods while using Slim4 like you did in the readme file for Slim3

use Fastroute\Dispatcher;
use Tuupola\Middleware\CorsMiddleware;

$app->add(
    new CorsMiddleware([
        "origin" => ["*"],
        "methods" => function($request) use ($app) {
            $container = $app->getContainer();
            $dispatch = $container["router"]->dispatch($request);
            if (Dispatcher::METHOD_NOT_ALLOWED === $dispatch[0]) {
                return $dispatch[1];
            }
        }
    ])
);

I've tried the following for Slim 4:

$app->addMiddleware(new Tuupola\Middleware\CorsMiddleware([
  'methods' => function ($request): array {
	$routeContext = RouteContext::fromRequest($request);
	$routingResults = $routeContext->getRoutingResults();
	$methods = $routingResults->getAllowedMethods();
	
	return $methods;
  },
]));

But either when I put $app->addRoutingMiddleware(); in front of the code block above I get the following error:

PHP Fatal error:  Uncaught RuntimeException: Cannot create RouteContext before routing has been completed in /var/www/html/vendor/slim/slim/Slim/Routing/RouteContext.php:40
Stack trace:
#0 /var/www/html/public/index.php(103): Slim\\Routing\\RouteContext::fromRequest()
#1 /var/www/html/vendor/tuupola/cors-middleware/src/CorsMiddleware.php(175): Closure->{closure}()
#2 /var/www/html/vendor/tuupola/cors-middleware/src/CorsMiddleware.php(91): Tuupola\\Middleware\\CorsMiddleware->buildSettings()
#3 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(147): Tuupola\\Middleware\\CorsMiddleware->process()
#4 /var/www/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(81): Psr\\Http\\Server\\RequestHandlerInterface@anonymous->handle()
#5 /var/www/html/vendor/slim/slim/Slim/App.php(215): Slim\\MiddlewareDispatcher->handle()
#6 /var/www/html/vendor/slim/slim/Slim/App.php(199): Slim\\App->handle()
#7 /var/www/html/public/index.php(127): Slim\\App->run()
#8 {main}
  thrown in /var/www/html/vendor/slim/slim/Slim/Routing/RouteContext.php on line 40

or when I put $app->addRoutingMiddleware(); after the code block, the Cors middleware doesn't get invoked.

I can mitigate the first error where it complains about the RouteContext when I implement a OPTIONS catch-all block like so:

$app->options('/{routes:.+}', function (ServerRequestInterface $request, ResponseInterface $response, $args): ResponseInterface {
  return $response;
});

But I wonder if I can get rid of the OPTIONS catch-all block altogether, what I'm missing here?

jk avatar Nov 10 '21 14:11 jk

I am not sure if I have ever used that feature with Slim 4. Most API projects I have are still Slim 3. I try to find if I have example somewhere. I just remember there has never been easy way to get that info.

tuupola avatar Nov 10 '21 15:11 tuupola

I have the same problem, some idea?

GoldraK avatar Mar 15 '22 15:03 GoldraK

same 👍🏻

killua-eu avatar May 15 '22 14:05 killua-eu

It works for me with the following config:

// init container
// ...

// init middleware
        $app->options('/{routes:.+}', fn ($request, $response, $args) => $response);

        $app->add(new CorsMiddleware([
            'logger' => $container->getLogger(),
            'origin' => array_merge(['http://localhost'], Settings::get('api.custom_safe_hosts')),
            'methods' => function (ServerRequest $request): array {
                $routeContext = RouteContext::fromRequest($request);
                $routingResults = $routeContext->getRoutingResults();

                return $routingResults->getAllowedMethods();
            },
            'headers.allow' => ['Authorization', 'If-Match', 'If-Unmodified-Since'],
            'headers.expose' => ['Authorization', 'Etag'],
            'credentials' => true,
            'cache' => 60,
            'error' => function (ServerRequest $request, \Slim\Psr7\Response $response, array $arguments) {
                $arguments['origin'] = $_SERVER['HTTP_ORIGIN'];

                return $response
                    ->withHeader('Content-Type', 'application/json')
                    ->withBody((new StreamFactory())->createStream(json_encode($arguments, \JSON_UNESCAPED_SLASHES | \JSON_PRETTY_PRINT)));
            },
        ]));

// init rest of middleware, including routing middleware
$app->run();

So apparently the OPTIONS catch-all block is really needed, as stated on https://www.slimframework.com/docs/v4/cookbook/enable-cors.html

mbolli avatar Jul 14 '22 06:07 mbolli