Slim 4 and attribute use in Middleware

Hi team,

I’m trying to share data between Middlewares using $request->withAttribute and $request->getAttribute using a before middleware, below n example:

    $app->add(function (Request $request, RequestHandler $handler) {
        $response = $handler->handle($request);
        $response->getBody()->write(' AFTER: ' . $request->getAttribute('foo'));
        return $response;
    });
    
    $app->get('/test', function (Request $request, Response $response, $args) {
        $response->getBody()->write('Hello World');
        $request = $request->withAttribute('foo', 'bar');
        return $response;
    });

But in the before Middleware, I’m unable to obtain the value and I don’t understand what I’m doing wrong.

Do you have any suggestions?

Thanks and regards.
Giuseppe

As soon as your action handler is executed, you can actually only manipulate the response, since the request is then already done.

Hi Oran,

Interesting, but this happens also using a before Middleware, see below example.
So for me it is unclear which is the best way to share content between middlewares.

Do you have any examples?

Thanks and regards.
Giuseppe

    $app->add(function (Request $request, RequestHandler $handler) {
        $request = $request->withAttribute('foo', 'bar');

        $response = $handler->handle($request);
        $existingContent = (string) $response->getBody();
    
        $response = new Slim\Psr7\Response();
        $response->getBody()->write('BEFORE ->' . $existingContent);
    
        return $response;
    });

    $app->get('/test', function (Request $request, Response $response) {
        $response->getBody()->write('Hello World');
        return $response;
    });

    $app->add(function (Request $request, RequestHandler $handler) {
        $response = $handler->handle($request);
        $response->getBody()->write(' <- AFTER: ' . $request->getAttribute('foo'));
        return $response;
    });

Usually an ingoing middleware is to check the incoming request object and an outgoing middleware is to change the response (object). So the shown example ExampleBeforeMiddleware in the documentation is quite confusing because it is an outgoing middleware.

If the response object is altered in the incoming middleware without actually returning a response from it, then changing something after the incoming middleware has no effect.

Hi Oran,

Thanks for the feedback.

This is a bit strange, in this way there are a lot of cases where middlewares are unable to “communicate” with each other.

I changed the POC, editing the before middleware to use the altered request object, but also in this way I was unable to share data with the after middleware

$app->add(function (Request $request, RequestHandler $handler) {
    $request = $request->withAttribute('foo', 'bar');

    $response = $handler->handle($request);
    $existingContent = (string) $response->getBody();

    $responseFactory = new Slim\Psr7\Factory\ResponseFactory();
    $newResponse = $responseFactory->createResponse();
    $newResponse->getBody()->write('BEFORE -> ' . $existingContent);

    return $newResponse;
});

Do you have any ideas?

Regards,
Giuseppe

In your case, it may depend on the order of the middleware stack. In Slim the middleware stack is LIFO (last in fist out). So the last middleware you add will be executed first. It’s not so easy to help here, because I don’t know much about your specific use case. Sorry.

1 Like

And this my friend, is the correct point, so in my problem there are two main points.

  1. The first one is about the action can’t manipulate the response, so I moved my logic inside a before Middlevare;

  2. The second one is about the LIFO order, so I moved the before middleware.

The working POC is in the following code, in this scenario the after middleware reads the attribute filled by the before middleware.

I would like to suggest to update the official documentation.

Thanks and regards.
Giuseppe

    $app->add(function (Request $request, RequestHandler $handler) {
        $response = $handler->handle($request);
        $response->getBody()->write(' <- AFTER: ' . $request->getAttribute('foo'));
        return $response;
    });

    $app->add(function (Request $request, RequestHandler $handler) {
        $request = $request->withAttribute('foo', 'bar');

        $response = $handler->handle($request);
        $existingContent = (string) $response->getBody();
    
        $response = new Slim\Psr7\Response();
        $response->getBody()->write('BEFORE -> ' . $existingContent);

        return $response;
    });

    $app->get('/test', function (Request $request, Response $response) {
        $response->getBody()->write('Hello World');
        return $response;
    });
1 Like