Middleware

You can run code before and after your Slim application to manipulate theRequest and Response objects as you see fit. This is called middleware.Why would you want to do this? Perhaps you want to protect your appfrom cross-site request forgery. Maybe you want to authenticate requestsbefore your app runs. Middleware is perfect for these scenarios.

What is middleware?

A middleware implements the PSR-15 Middleware Interface:

  • Psr\Http\Message\ServerRequestInterface - The PSR-7 request object
  • Psr\Http\Server\RequestHandlerInterface - The PSR-15 request handler objectIt can do whatever is appropriate with these objects. The only hard requirementis that a middleware MUST return an instance of Psr\Http\Message\ResponseInterface.Each middleware SHOULD invoke the next middleware and pass it Request andResponse objects as arguments.

How does middleware work?

Different frameworks use middleware differently. Slim adds middleware as concentriclayers surrounding your core application. Each new middleware layer surroundsany existing middleware layers. The concentric structure expands outwardly asadditional middleware layers are added.

The last middleware layer added is the first to be executed.

When you run the Slim application, the Request object traverses themiddleware structure from the outside in. They first enter the outer-most middleware,then the next outer-most middleware, (and so on), until they ultimately arriveat the Slim application itself. After the Slim application dispatches theappropriate route, the resultant Response object exits the Slim application andtraverses the middleware structure from the inside out. Ultimately, a finalResponse object exits the outer-most middleware, is serialized into a raw HTTPresponse, and is returned to the HTTP client. Here’s a diagram that illustratesthe middleware process flow:

Middleware architecture

How do I write middleware?

Middleware is a callable that accepts two arguments: a Request object and a RequestHandler object. Each middleware MUST return an instance of Psr\Http\Message\ResponseInterface.

Closure middleware example.

This example middleware is a Closure.

  1. <?php
  2. use Psr\Http\Message\ServerRequestInterface as Request;
  3. use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
  4. use Slim\Factory\AppFactory;
  5. use Slim\Psr7\Response;
  6. require __DIR__ . '/../vendor/autoload.php';
  7. $app = AppFactory::create();
  8. /`
  9. * Example middleware closure
  10. *
  11. * @param ServerRequest $request PSR-7 request
  12. * @param RequestHandler $handler PSR-15 request handler
  13. *
  14. * @return Response
  15. */
  16. $beforeMiddleware = function (Request $request, RequestHandler $handler) {
  17. $response = $handler->handle($request);
  18. $existingContent = (string) $response->getBody();
  19. $response = new Response();
  20. $response->getBody()->write('BEFORE' . $existingContent);
  21. return $response;
  22. };
  23. $afterMiddleware = function ($request, $handler) {
  24. $response = $handler->handle($request);
  25. $response->getBody()->write('AFTER');
  26. return $response;
  27. };
  28. $app->add($beforeMiddleware);
  29. $app->add($afterMiddleware);
  30. // ...
  31. $app->run();

Invokable class middleware example

This example middleware is an invokable class that implements the magic __invoke() method.

  1. <?php
  2. use Psr\Http\Message\ServerRequestInterface as Request;
  3. use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
  4. use Slim\Psr7\Response;
  5. class ExampleBeforeMiddleware
  6. {
  7. /**
  8. * Example middleware invokable class
  9. *
  10. * @param ServerRequest $request PSR-7 request
  11. * @param RequestHandler $handler PSR-15 request handler
  12. *
  13. * @return Response
  14. */
  15. public function __invoke(Request $request, RequestHandler $handler): Response
  16. {
  17. $response = $handler->handle($request);
  18. $existingContent = (string) $response->getBody();
  19. $response = new Response();
  20. $response->getBody()->write('BEFORE' . $existingContent);
  21. return $response;
  22. }
  23. }
  1. <?php
  2. use Psr\Http\Message\ResponseInterface as Response;
  3. use Psr\Http\Message\ServerRequestInterface as Request;
  4. use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
  5. class ExampleAfterMiddleware
  6. {
  7. /**
  8. * Example middleware invokable class
  9. *
  10. * @param ServerRequest $request PSR-7 request
  11. * @param RequestHandler $handler PSR-15 request handler
  12. *
  13. * @return Response
  14. */
  15. public function __invoke(Request $request, RequestHandler $handler): Response
  16. {
  17. $response = $handler->handle($request);
  18. $response->getBody()->write('AFTER');
  19. return $response;
  20. }
  21. }

To use these classes as a middleware, you can use add(new ExampleMiddleware()); function chain after the $app route mapping methods get(), post(), put(), patch(), delete(), options(), any() or group(), which in the code below, any one of these, could represent $subject.

  1. <?php
  2. use Slim\Factory\AppFactory;
  3. require __DIR__ . '/../vendor/autoload.php';
  4. $app = AppFactory::create();
  5. // Add Middleware On App
  6. $app->add(new ExampleMiddleware());
  7. // Add Middleware On Route
  8. $app->get('/', function () { ... })->add(new ExampleMiddleware());
  9. // Add Middleware On Group
  10. $app->group('/', function () { ... })->add(new ExampleMiddleware());
  11. // ...
  12. $app->run();

How do I add middleware?

You may add middleware to a Slim application, to an individual Slim application route or to a route group. All scenarios accept the same middleware and implement the same middleware interface.

Application middleware

Application middleware is invoked for every incoming HTTP request. Add application middleware with the Slim application instance’s add() method. This example adds the Closure middleware example above:

  1. <?php
  2. use Psr\Http\Message\ServerRequestInterface as Request;
  3. use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
  4. use Slim\Factory\AppFactory;
  5. use Slim\Psr7\Response;
  6. require __DIR__ . '/../vendor/autoload.php';
  7. $app = AppFactory::create();
  8. $app->add(function (Request $request, RequestHandler $handler) {
  9. $response = $handler->handle($request);
  10. $existingContent = (string) $response->getBody();
  11. $response = new Response();
  12. $response->getBody()->write('BEFORE ' . $existingContent);
  13. return $response;
  14. });
  15. $app->add(function (Request $request, RequestHandler $handler) {
  16. $response = $handler->handle($request);
  17. $response->getBody()->write(' AFTER');
  18. return $response;
  19. });
  20. $app->get('/', function (Request $request, Response $response, $args) {
  21. $response->getBody()->write('Hello World');
  22. return $response;
  23. });
  24. $app->run();

This would output this HTTP response body:

  1. BEFORE Hello World AFTER

Route middleware

Route middleware is invoked only if its route matches the current HTTP request method and URI. Route middleware is specified immediately after you invoke any of the Slim application’s routing methods (e.g., get() or post()). Each routing method returns an instance of \Slim\Route, and this class provides the same middleware interface as the Slim application instance. Add middleware to a Route with the Route instance’s add() method. This example adds the Closure middleware example above:

  1. <?php
  2. use Psr\Http\Message\ResponseInterface as Response;
  3. use Psr\Http\Message\ServerRequestInterface as Request;
  4. use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
  5. use Slim\Factory\AppFactory;
  6. require __DIR__ . '/../vendor/autoload.php';
  7. $app = AppFactory::create();
  8. $mw = function (Request $request, RequestHandler $handler) {
  9. $response = $handler->handle($request);
  10. $response->getBody()->write('World');
  11. return $response;
  12. };
  13. $app->get('/', function (Request $request, Response $response, $args) {
  14. $response->getBody()->write('Hello ');
  15. return $response;
  16. })->add($mw);
  17. $app->run();

This would output this HTTP response body:

  1. Hello World

Group middleware

In addition to the overall application, and standard routes being able to accept middleware, the group() multi-route definition functionality, also allows individual routes internally. Route group middleware is invoked only if its route matches one of the defined HTTP request methods and URIs from the group. To add middleware within the callback, and entire-group middleware to be set by chaining add() after the group() method.

Sample Application, making use of callback middleware on a group of url-handlers

  1. <?php
  2. use Psr\Http\Message\ResponseInterface as Response;
  3. use Psr\Http\Message\ServerRequestInterface as Request;
  4. use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
  5. use Slim\Factory\AppFactory;
  6. use Slim\Routing\RouteCollectorProxy;
  7. require __DIR__ . '/../vendor/autoload.php';
  8. $app = AppFactory::create();
  9. $app->get('/', function (Request $request, Response $response) {
  10. return $response->getBody()->write('Hello World');
  11. });
  12. $app->group('/utils', function (RouteCollectorProxy $group) {
  13. $group->get('/date', function (Request $request, Response $response) {
  14. $response->getBody()->write(date('Y-m-d H:i:s'));
  15. return $response;
  16. });
  17. $group->get('/time', function (Request $request, Response $response) {
  18. $response->getBody()->write((string)time());
  19. return $response;
  20. });
  21. })->add(function (Request $request, RequestHandler $handler) use ($app) {
  22. $response = $handler->handle($request);
  23. $dateOrTime = (string) $response->getBody();
  24. $response = $app->getResponseFactory()->createResponse();
  25. $response->getBody()->write('It is now ' . $dateOrTime . '. Enjoy!');
  26. return $response;
  27. });
  28. $app->run();

When calling the /utils/date method, this would output a string similar to the below

  1. It is now 2015-07-06 03:11:01. Enjoy!

Visiting /utils/time would output a string similar to the below

  1. It is now 1436148762. Enjoy!

But visiting /(domain-root), would be expected to generate the following output as no middleware has been assigned

  1. Hello World

Passing variables from middleware

The easiest way to pass attributes from middleware is to use the request’sattributes.

Setting the variable in the middleware:

  1. $request = $request->withAttribute('foo', 'bar');

Getting the variable in the route callback:

  1. $foo = $request->getAttribute('foo');

Finding available middleware

You may find a PSR-15 Middleware class already written that will satisfy your needs. Here are a few unofficial lists to search.