REST API in Slim 3 Framework – Part 1

…Continued from previous page. Go to Table of Contents.

Getting Started

[back to top]

The Slim Framework is a PHP micro framework that helps PHP developers quickly and easily write web applications and APIs. We’re going to focus primarily on the API features, but by creating our first Slim app, you’ll see how quickly a dynamic web application comes together. We’ll spend a bit of time exploring the bits that make that web app work before converting it to an API-only application.

Create a Slim 3 Project

[back to top]

Creating a Slim project is as simple as using composer to create a project for us using the Slim Skeleton.

$ cd ~/Projects
$ composer create-project slim/slim-skeleton api-v1-books
animation of composer install
It’s really as easy as that. You have a fully functioning Slim application.

Run Your Project

[back to top]

To confirm this, let’s change into the app directory and run it locally with simple PHP:

$ cd api-v1-books
$ php -S localhost:8080 -t public public/index.php

If you open a browser to http://localhost:8080/, you’ll see your very first Slim application running.

Slim framework in the browser
HINT: try adding your name after the url, like http://localhost:8080/adam, for instance. We’ll explore how that works in the next section.

Explore Slim 3

[back to top]

If we have a look at the folder structure in our Slim project you’ll see it’s pretty clean and well organised. src, templates and test will be your main working directories, while public holds your main entry point to the application (you won’t do much in there but we’ll explore it anyway. Finally, the vendor directory is where composer stores all the 3rd part dependencies.

├── logs
│   └──
├── public
│   └── index.php
├── src
│   ├── dependencies.php
│   ├── middleware.php
│   ├── routes.php
│   └── settings.php
├── templates
│   └── index.phtml
├── tests
│   └── Functional
├── vendor
│   ├── autoload.php
│   ├── bin
~   ~
~   ~
│   ├── symfony
│   └── webmozart
├── composer.json
├── composer.lock
├── docker-compose.yml
├── phpunit.xml

public folder

[back to top]

As the name would suggest, the public folder contains the outward facing stuff, most importantly the index.php. This file is like your main(), your init() your MainActivity, your AppDelegate… you get the idea. In the web world, the index.* is our main entry point.

Inside index.php you’ll fine something that looks like a lot of modern web apps these days. Some required packages, an app instance, app execution… there’s settings, dependencies, middleware and routes. Sounds like most web apps, both front end and backend.

if (PHP_SAPI == 'cli-server') {
    // To help the built-in PHP dev server, check if the request was actually for
    // something which should probably be served as a static file
    $url  = parse_url($_SERVER['REQUEST_URI']);
    $file = __DIR__ . $url['path'];
    if (is_file($file)) {
        return false;

require __DIR__ . '/../vendor/autoload.php';


// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$app = new \Slim\App($settings);

// Set up dependencies
require __DIR__ . '/../src/dependencies.php';

// Register middleware
require __DIR__ . '/../src/middleware.php';

// Register routes
require __DIR__ . '/../src/routes.php';

// Run app

src folder

[back to top]


Let’s start with settings.php. It’s an array with some key value pairs that tell Slim where to find templates, loggers and more. You can find more settings in the Slim documentation. Notice there is a rendered setting that tells Slim where to find templates. We won’t need this in our REST api so we’ll come back to this later and remove it. But for now, just take note that it’s here. The other main section of this file is the logger settings. Both of these settings will have a direct relationship with the next file we look at.

return [
    'settings' => [
        'displayErrorDetails' => true, // set to false in production
        'addContentLengthHeader' => false, // Allow the web server to send the content-length header

        // Renderer settings
        'renderer' => [
            'template_path' => __DIR__ . '/../templates/',

        // Monolog settings
        'logger' => [
            'name' => 'slim-app',
            'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log',
            'level' => \Monolog\Logger::DEBUG,

Next we’ll look at dependencies.php. Slim uses a dependency container to prepare, manage, and inject application dependencies. And that’s what you see happening here — a renderer and logger method are made available to $app and reference the settings.renderer and settings.logger values in settings.php respectively.

Again, we won’t need the renderer for our api, but we’ll leave it for now so we can play around with the web app for familiarity.

// DIC configuration

$container = $app->getContainer();

// view renderer
$container['renderer'] = function ($c) {
    $settings = $c->get('settings')['renderer'];
    return new Slim\Views\PhpRenderer($settings['template_path']);

// monolog
$container['logger'] = function ($c) {
    $settings = $c->get('settings')['logger'];
    $logger = new Monolog\Logger($settings['name']);
    $logger->pushProcessor(new Monolog\Processor\UidProcessor());
    $logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], $settings['level']));
    return $logger;

We’ll skip over the middleware.php file (because it’s empty by default) but we’ll be getting into middleware quite a bit in future installments of this series. Just know that middleware in Slim is just like middleware in other frameworks, like Express.js, where it can perform pre and post flow manipulation of an event stream. So an http requests and responses can be manipulated as required.


Finally I want to look at routes.php, the neural network of any web application, and eventbus of sorts between the outside world and your controllers. Our router currently has one route, which is the base path of / with the optional parameter of [{name}]. Remember earlier when you added a name to the end of the URL and it changed the output of the webpage? This route is the first step in making that happen. The route callback function returns a renderer that passes the response and arguments (name in this case), to the index.phtml template and renders it.


use Slim\Http\Request;
use Slim\Http\Response;

// Routes

$app->get('/[{name}]', function (Request $request, Response $response, array $args) {
    // Sample log message
    $this->logger->info("Slim-Skeleton '/' route");

    // Render index view
    return $this->renderer->render($response, 'index.phtml', $args);

templates folder

[back to top]

In the templates folder you’ll find one file, index.phtml. This is the UI that is rendered when we hit the url http://localhost:8080 or http://localhost:8080/adam. Our REST api won’t use this folder at all, but after we have Homestead installed, we’ll play around with this file just so you can understand the connection between the route and the template. Notice that $name seems to come out of nowhere? That is actually a pointer to $args["name"] that we passed in to the renderer from the routes.php.

<!DOCTYPE html>
        <meta charset="utf-8"/>
        <title>Slim 3</title>
        <link href='//' rel='stylesheet' type='text/css'>
            body {
                margin: 50px 0 0 0;
                padding: 0;
                width: 100%;
                font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                text-align: center;
                color: #aaa;
                font-size: 18px;

            h1 {
                color: #719e40;
                letter-spacing: -3px;
                font-family: 'Lato', sans-serif;
                font-size: 100px;
                font-weight: 200;
                margin-bottom: 0;
        <div>a microframework for PHP</div>

        <?php if (isset($name)) : ?>
            <h2>Hello <?= htmlspecialchars($name); ?>!</h2>
        <?php else: ?>
            <p>Try <a href="">SlimFramework</a></p>
        <?php endif; ?>

Continue reading on the next page…

Pages: 1 2 3