First steps with the Slim framework

In this section, you will take you first steps with the Slim framework. For this, you will first use Composer to install the framework and then build a small sample application that will show you the basic principles of the framework.

Installing Slim

The Slim framework can be easily installed using Composer. It requires PHP in at least version 5.5, but also works well with PHP 7. Start by initializing a new project with Composer:

$ composer init .

This will create a new project-level composer.json file for our project. Now you can add the slim/slim package as a dependency:

$ composer require slim/slim

A small sample application

You can now start using the Slim framework in your PHP application. For this, create an index.php file in your web server's document root with the following content:

<?php 
use SlimApp; 
use SlimHttpRequest; 
use SlimHttpResponse; 
 
require "vendor/autoload.php"; 
 
$app = new App(); 
$app->get("/", function(Request $req, Response $res): Response { 
    return $res->withJson(["message" => "Hello World!"]); 
}); 
$app->run(); 

Let's have a look at how the Slim framework works here. The central object here is the $app variable, an instance of the SlimApp class. You can then use this application instance to register routes. Each route is a mapping of an HTTP request path to a simple callback function that handles an HTTP request. These handler functions need to accept a request and a response object and need to return a new response object.

Before you can test this application, you may need to configure your web server to rewrite all requests to your index.php file. If you are using Apache as a web server, this can be done with a simple .htaccess file in your document root:

RewriteEngine on 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^([^?]*)$ /index.php [NC,L,QSA] 

This configuration will rewrite requests for all URLs to your index.php file.

You can test your (admittedly still very simple) API with your browser. If you prefer the command line, I can recommend the HTTPie command-line tool. HTTPie is Python-based and you can easily install it using your operating system's package manager or Python's own package manager, pip:

apt-get install httpie
# Alternatively:
pip install --upgrade httpie

You can then use HTTPie on the command-line to perform RESTful HTTP requests easily and also get syntax-highlighted output. See the following figure for an example output of HTTPie when used with the example application:

A small sample application

Example output of HTTPie with the Slim example application

Accepting URL parameters

Slim routes can also contain parameters in their path. In your index.php, add the following route before the last $app->run() statement:

$app->get( 
    '/users/{username}', 
    function(Request $req, Response $res, array $args): Response { 
        return $res->withJson([ 
          'message' => 'Hello ' . $args['username' 
        ]); 
    } 
); 

As you can see, any route specification can contain arbitrary parameters in curly brackets. The route handler function can then accept a third parameter that contains all path parameters from the URL as an associative array (such as the username parameter in the preceding example).

Accepting HTTP requests with a message body

So far, you have only worked with HTTP GET requests. Of course, the Slim framework also supports any other kind of request method that is defined by the HTTP protocol. One interesting difference between a GET and - for example - a POST request, however, is that some requests (such as POST, PUT, and others) can contain a request body.

The request body consists of structured data that is serialized as a string according to some pre-defined encoding. When sending a request to a server, the client uses the Content-Type HTTP header to tell the server which encoding is used for the request body. Common encodings include the following:

  • application/x-www-form-urlencoded is typically used by browsers when submitting an HTML form
  • application/json for JSON encoding
  • application/xml or text/xml for XML encoding

Luckily, the Slim framework supports all these encodings and determines the correct method to parse a request body automatically. You can test this with the following simple route handler:

$app->post('/users', function(Request $req, Response $res): Response { 
    $body = $req->getParsedBody(); 
    return $response->withJson([ 
        'message' => 'creating user ' . $body['username'] 
    ]); 
}); 

Note the use of the getParsedBody() method that is offered by the Request class. This method will use the request body and automatically use the correct decoding method depending on the Content-Type header that was present in the request.

You can now use any of the preceding content encodings presented to POST data to this route. This can be easily tested using the following curl commands:

$ curl -d '&username=martin&firstname=Martin&lastname=Helmich' http://localhost/users 
$ curl -d '{"username":"martin","firstname":"Martin","lastname":"Helmich"}' -H'Content-Type: application/json' http://localhost/users
$ curl -d '<user><username>martin</username><firstname>Martin</firstname><lastname>Helmich</lastname></user>' -H'Content-Type: application/xml'

All of these requests will yield the same response from your Slim application, as they're containing the exact same data, just using a different content encoding.

The PSR-7 standard

One of the Slim framework's main features is the PSR-7 compliance. PSR-7 is a PHP Standard Recommendation (PSR) defined by the PHP Framework Interoperability Group (FIG) and describes a set of standard interfaces that can be implemented by HTTP servers and client libraries written in PHP to increase operability between those products (or in plain English, to enable these libraries to be used with each other).

PSR-7 defines a set of PHP interfaces that the framework can implement. The following figure illustrates the interfaces that are defined by the PSR-7 standard. You can even install these interfaces in your project by acquiring the psr/http-messages package using Composer:

The PSR-7 standard

The interfaces defined by the PSR-7 standard

The SlimHttpRequest and SlimHttpResponse classes that you have worked with in the previous examples already implement these PSR-7 interfaces (the SlimHttpRequest class implements the ServerRequestInterface and SlimHttpResponse implements ResponseInterface).

These standardized interfaces become especially useful when you want to use two different HTTP libraries together. As an interesting example, consider a PSR-7 compliant HTTP server framework like Slim used together with a PSR-7 compliant client library, for example Guzzle (use the package key guzzlehttp/guzzle if you want to install it with Composer). You can use these two libraries and easily wire them together for a dead-simple reverse proxy:

$httpClient = new GuzzleHttpClient(); 
 
$app = new SlimApp(); 
$app->any('{path:.*}', 
    function( 
        ServerRequestInterface $req, 
        ResponseInterface $response 
    ) use ($client): ResponseInterface { 
        return $client->send( 
            $request->withUri( 
                $request->getUrl()->withHost('your-upstream-server.local') 
            ) 
        ); 
    } 
); 

What exactly happens here? The Slim request handler gets an implementation of the ServerRequestInterface passed as a first parameter (remember; this interface inherits the regular RequestInterface) and needs to return a ResponseInterface implementation. Conveniently, the send() method of GuzzleHttpClient also accepts a RequestInterface and returns a ResponseInterface. Because of this, you can simply re-use the request object that you received in your handler and pipe it into the Guzzle client and also re-use the response object returned by the Guzzle client. Guzzle's send() method actually returns an instance of the GuzzleHttpPsr7Response class (and not SlimHttpResponse). That is completely acceptable, as both of these classes implement the same interface. In addition, the preceding example uses the method defined by the PSR-7 interfaces to modify the host part of the request URI.

Tip

Immutable Objects You may have wondered about the withUri and withHost methods in the preceding code example. Why do the PSR-7 interfaces not imply declare methods such as setUri or setHost? The answer is that all PSR-7 implementations are designed to be immutable. This means that objects are not intended to be modified after they are created. All the methods starting with with (and PSR-7 actually defines a lot of them) are designed to return a copy of the original object with one modified property. So basically, instead of modifying objects with setter methods, you'll be passing around clones of an original object:

// using mutable objects (not supported by PSR-7)

$uri->setHost('foobar.com');

// using immutable objects

$uri = $uri->withHOst('foobar.com');

Middleware

Middleware is one of the most important features of the Slim framework and similar libraries. It allows you to modify an HTTP request before it is passed to the actual request handler, modify an HTTP response after being returned from the request handler, or bypass a request handler entirely. There are quite a number of possible use cases for this:

  • You can handle authentication and authorization in middleware. Authentication encompasses identifying a user from given request parameters (maybe the HTTP request contains an authorization header or a cookie with a session ID) and authorization involves checking if the authenticated user is actually allowed to access a particular resource.
  • You can implement a rate limiting for your API by counting requests by a particular user and returning with an error response code early before hitting the actual request handler.
  • In general, all kinds of operations that enrich a request with additional data before being processed by the request handler.

Middleware is also chainable. The framework can manage any number of middleware components, and an incoming request will be piped through all registered middleware. Each item of middleware must be callable as a function and accept a RequestInterface, a ResponseInterface, and a function that represents the next instance of middleware (or the request handler itself).

The following code example shows middleware that adds an (admittedly extremely simple) HTTP authentication to an application:

$app->add(function (Request $req, Response $res, callable $next): Response {
    $auth = $req->getHeader('Authorization');
    if (!$auth) {
        return $res->withStatus(401);
    }
    if (substr($auth, 0, 6) !== 'Basic ' ||
        base64_decode(substr($auth, 6)) !== 'admin:secret') {
        return $res->withStatus(401);
    }
    return $next($req, $res);
}

$app->get('/users/{username}', function(Request $req, Response $res): Response {
    // Handle the request
});
 
$app->get('/users/{username}', function(Request $req, Response $res): Response { 
    // Handle the request 
}); 

The $app->add() function can be used to register middleware that will be invoked on any request. As you can see, the middleware function itself looks similar to a regular request handler, with the only difference being the third parameter, $next. Each request can be passed through a potentially indeterminate amount of middleware. The $next function gives a component of middleware control over whether a request should be passed to the next component of middleware in the chain (or the registered request handler itself). It is important to note, however, that the middleware does not have to call the $next function at any time. In the preceding example, an unauthorized HTTP request will never even get through to the actual request handler, because the middleware that handles authentication does not invoke $next at all when there is no valid authentication.

This is where PSR-7 comes into play. Because of PSR-7, you can develop and distribute middleware and they will work with all frameworks and libraries that also implement PSR-7. This guarantees interoperability between libraries and also ensures that there is a shared ecosystem of libraries that can be widely re-used. A simple Internet search for PSR-7 middlewares yields a plethora of libraries that you can use nearly out-of-the box.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.189.251