Creating the simplest possible API with Symfony 4 and Docker

Complex API, built in Italy with 💚

On November 30th 2017, Symfony team released the fourth version of the framework, Symfony 4. This version has lots of new features and modifies relevant aspects of older versions [1]:

  • application bundles has been removed
  • configuration parameters becomes environment variables
  • improvements to the application directory structure
  • Symfony Flex: the new tool to automatate repetitive tasks
  • a smaller codebase

To test the installation process, I create a simple API; to be more precise, I create the simplest possible API in my opinion: a back-end with only one route, /ping, which will respond with the following JSON:

{
     “ping”: “pong”
}

Ok, it’s not the most exciting thing I’ve ever done, but it’s simple and fast.

Oh, and another thing: I will use Docker to create the development environment. Normally I use Vagrant and Puppet for Symfony-based projects, but I would like to test how Docker works in this use case.

So, let’s begin.

Install Docker (Community Edition). I won’t write how to install Docker in your system. You can find how to do that here: https://www.docker.com/community-edition#/download. Just for information, I use Docker for Mac (version 18.03.0-ce-rc4-mac57).

I don’t want to write custom Dockerfiles (I’m lazy and I don’t want to waste a morning to test them). A 30-second Google search allows me to find this repository on GitHub: https://github.com/eko/docker-symfony.

This is a complete stack for running Symfony 4 (latest version: Flex) into Docker containers using docker-compose tool.

669 stars, 284 forks and last commit: 15 days ago. Cool.

Just for information, the hash of the commit of the repo I will use for the project is b553a7d6b64f024c72790346943cb5f3986274dc.

git clone https://github.com/eko/docker-symfony simple-api
cd simple-api
docker-compose up -d

Hopefully, you won’t receive any error:

Creating simpleapi_db_1 … done
Creating simpleapi_php_1 … done
Creating simpleapi_nginx_1 … done
Creating simpleapi_elk_1 … done

With the command

docker ps

you will have the ids of the container (in the “CONTAINER ID” column). In my case, the image simpleapi_php has the following container id: 6ccf4ca77b10. We will use it in a moment.

You can install the new Symfony framework with the command:

docker exec 6ccf4ca77b10 composer create-project symfony/website-skeleton my-project

with 6ccf4ca77b10 your simpleapi_php container id. With this command, we in fact run the command

composer create-project symfony/website-skeleton my-project

in the container where composer has been installed during the composer up process.

I hope you won’t receive any error.

Now you have a folder ./symfony with ./symfony/var and ./symfony/my-project as subfolders. You have to move ./symfony/my-project files in ./symfony parent folder (after removing the useless ./symfony/my-project/var folder). At the end, you will have all Symfony files and directories (assets, bin, config, public, src, templates, etc.) in the ./symfony folder.

If you want to use git to version your code, you have to remove /symfony from the .gitignore file. Now you can commit your Symfony application code.

You can modify/delete also the LICENSE file and the README file.

You have to change your /etc/hosts file to allow your system using the host symfony.localhost. Add the following line at the end of the file:

127.0.0.1 symfony.localhost

Open your browser and go to symfony.localhost.

Oh, we have an error. But it’s a 404 Symfony error!

No route found for “GET /”
A fantastic Symfony error page

Nothing to worry about! We haven’t any route at the moment, so it’s normal!

We can write a route just for testing. With your favorite editor, create a file in the .symfony/src/Controller folder. Somtehing like HelloController.php:

<?php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HelloController
{
  /**
  * @Route(“/hello”)
  */
  public function helloAction()
  {
    return new Response(
      ‘<html><body>Hello World</body></html>’
    );
  }
}

It’s a pretty simple Controller, in which we define a route /hello which responds with a HTML string.

Now go to symfony.localhost/hello with your browser and you will see “Hello World”. Wow.

But we would like to have a JSON response, so we change this file, renaming it from HelloController.php to PingController.php, and modifying the code a little bit:

<?php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class PingController
{
  /**
  * @Route(“/ping”)
  */
  public function pingAction()
  {
    $response = new Response();
    $response->setContent(json_encode(array(
      ‘ping’ => ‘pong’,
    )));
    $response->headers->set(‘Content-Type’, ‘application/json’);
    
return $response;
  }
}

UPDATE: As pointed out by Patrick Landolt, you can write also:

<?php

namespace App\Controller;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;

class PingController
{
  /**
  * @Route("/ping")
  */
  public function pingAction()
  {
    $response = new JsonResponse(array('ping' => 'pong'));

    return $response;
  }
}

Go to symfony.localhost/ping and jubilate with your favorite beer.

If you have lost something, you can read the code in the repository https://github.com/nicolanrizzo/simple-api.

But I have to write a real application, not a toy project!

We have seen how to return a simple JSON response. For a real application, you can use api-platform: https://api-platform.com.

https://api-platform.com