# Feedback & Question: Middleware and Response in Slim 4

**URL:** <https://discourse.slimframework.com/t/feedback-question-middleware-and-response-in-slim-4/3996>\
**Category:** Questions\
**Created:** [April 2, 2020, 12:36pm UTC](https://discourse.slimframework.com/t/feedback-question-middleware-and-response-in-slim-4/3996 "2020-04-02T12:36:29Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![fabswt](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/fabswt/32/1110_2.png) [@fabswt](https://discourse.slimframework.com/u/fabswt)\
**Post date:** [April 2, 2020, 12:36pm UTC](https://discourse.slimframework.com/t/feedback-question-middleware-and-response-in-slim-4/3996/1 "2020-04-02T12:36:29Z")

</div>

I’m done migrating to Slim 4 (from Slim 2 with a brief stop by Slim 3.) I got my Middleware working, but I wouldn’t say I’m happy with it.

# The docs

## Unclear

I don’t get it… The docs say:

> Each middleware SHOULD invoke the next middleware and pass it Request and  
> Response objects as arguments.

Looks like a relic from Slim 3:

- Slim 3 did use `__invoke(Request $request, Response $response, callable $next)`.
- Slim 4 uses `__invoke(Request $request, RequestHandler $handler)` – no  
`$response`.

> Each middleware MUST return an instance of  
> `Psr\Http\Message\ResponseInterface`.

But then two out of three examples that come after it use `Slim\Psr7\Response`, with the third one using `Psr\Http\Message\ResponseInterface`.

So which one is it, `Slim\Psr7\Response` or `Psr\Http\Message\ResponseInterface`?

## Bad example

The [ExampleBeforeMiddleware](http://www.slimframework.com/docs/v4/concepts/middleware.html#invokable-class-middleware-example) example **will break any redirect**. Because it creates a new Response and only copies the old body, any redirect set further down the middlewares layers will be lost.

One way to fix it would be to _replace_ the body of a response instead of creating a brand new Response. But how to do it? I understand we’re supposed to rely on StreamInterface but couldn’t find an example.

Another way would be to create a new Response, but copy the headers. **Is there a one-liner to copy the headers** , like there is for copying the body (with `(string) $response->getBody()`)?

# Accessing response in the Middleware

In v3, accessing the response before accessing the next middleware layer was  
straightforward and the logic easy to read. e.g.:

```php
public function __invoke(Request $request, Response $response, callable $next)
{
/**
 * Do stuff BEFORE passing to the next Middleware layer.
 * Example here is part of a Login middleware.
 * In this case, `before` checks for credentials and set cookies and redirect
 * as needed.
 */
$response = $this->before($request, $response);

/**
 * Invoke the next Middleware layer.
 * "Each middleware SHOULD invoke the next middleware and pass it
 * Request and Response objects as arguments."
 *
 * Don't run it for redirects as this is not needed (we're redirecting!)
 * and would break the app.
 */
if (! $response->isRedirect()) {
    $response = $next($request, $response);
}

/**
 * Do stuff AFTER the route is rendered.
 * e.g. `$response->getBody()->write('AFTER');`
 * e.g. `$response = $this->after($request, $response);` for symmetry.
 */
// Nothing to do for now.

/**
 * Finally, return the response.
 * "a middleware MUST return an instance of \Psr\Http\Message\ResponseInterface"
 */
return $response;
}

```

In v4, I’m confused… **How to get the response BEFORE running the next level of  
middleware?** Seems I have to create a new response all the time. So this makes me  
wonder: in v3, was the $response at the beginning of `_invoke` actually always  
empty too?

Thanks for the clarifications,  
Fabien

---

<div class="post-metadata">

**Author:** ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)\
**Post date:** [April 2, 2020, 3:52pm UTC](https://discourse.slimframework.com/t/feedback-question-middleware-and-response-in-slim-4/3996/2 "2020-04-02T15:52:13Z")

</div>

> [@fabswt](#):
>
> Looks like a relic from Slim 3:

Yes, that’s an relict from Slim 3 and should be fixed.

> So which one is it, `Slim\Psr7\Response` or `Psr\Http\Message\ResponseInterface` ?

In a perfect world we should always implement against the PSR-7 / PSR-15 interfaces and not the real implementation. So it should be:

- `Psr\Http\Message\ServerRequestInterface` (for the request object)
- `Psr\Http\Message\ResponseInterface` (for the response object)

### ExampleBeforeMiddleware

The [ExampleBeforeMiddleware](http://www.slimframework.com/docs/v4/concepts/middleware.html#invokable-class-middleware-example) is also not a “correct” PSR-15 middleware.

Accodring to [PSR-15](https://www.php-fig.org/psr/psr-15/) a middleware must implement the `Psr\Http\Server\MiddlewareInterface` interface. And the signature must look like this:

`public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface`

> The [ExampleBeforeMiddleware](http://www.slimframework.com/docs/v4/concepts/middleware.html#invokable-class-middleware-example) example **will break any redirect**. Because it creates a new Response and only copies the old body, any redirect set further down the middlewares layers will be lost.

You are right. This example in the docs is confusing (and wrong). Don’t overwrite the response object you already get from the handle method. If you do it, all other response data will get lost. Just use the response from the `handle()` method and it should be good.

### Accessing the response

To get the response just invoke the handle method:

`$response = $handler->handle($request);`

You can also create a response by using the ResponseFactory before you invoke the handle() method.  
For example:

`$response = $this->responseFactory->createResponse();`

To get access could als the ResponseFactory, you must inject it into your middleware via constructor injection.

> How to get the response BEFORE running the next level of middleware?

Only by **creating** your own response via the ResponseFactory or by instantiating it manually:

`$response = new \Slim\Psr7\Response();`

Full example:

```php
<?php

namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * Middleware.
 */
final class ExampleMiddleware implements MiddlewareInterface
{
    /**
     * Invoke middleware.
     *
     * @param ServerRequestInterface $request The request
     * @param RequestHandlerInterface $handler The handler
     *
     * @return ResponseInterface The response
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // Optional: create a new response (depends on the use case)
        //$response = new \Slim\Psr7\Response();

        // Invoke the next middleware and fetch the response
        $response = $handler->handle($request);

        // Do something with the response
        $response = $response->withHeader('X-Demo', 'test');

        return $response;
    }
}

```
