PHP Symfony REST API introduction

In this article you can learn how to start developing PHP RESTful  API -, a.k.a Getting started with symfony RESTful API by using Symfony's FOSRestBundle.

When you want just to make one or two controllers returning JSON, it might have no sense to learn how yet another bundle works, however FOSRestBundle can be very helpful in saving you time and extra typing when you're creating something more than that.

Installation & configuration

Let's say that for simplicity reasons we've installed symfony in a standard way:

$ symfony new testing

Befooe we install FOSRestBundle, we need to have installed and configured JMSSerializerBundle, so we need to run:

$ composer require jms/serializer-bundle

Then of course we need to add this bundle to the bundle list, if it's not been added yet:

// bundles.php

return [
    ...
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
    FOS\RestBundle\FOSRestBundle::class => ['all' => true],
    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
    Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
    ...
];

After that we need to install FOSRestBundle and add it also the bundle list:

$ composer require friendsofsymfony/rest-bundle

We also need to install one more bundle to be able to use annotations properly:

$ composer require annotations

Also twig bundle and SensioFrameworkExtraBundle needs to be installed in the same way:

$ composer require symfony/twig-bundle sensio/framework-extra-bundle;

Building simple RESTful controller

Let's build a simple RESTful api for managing toys.

Now we can start building our app creating first Symfony MVC's controller:

I'm going to use maker bundle to save some time for typing code for controller, so if you don't have it installed yet, you can do it like this:

$  composer require symfony/maker-bundle --dev

Then we need to run:

$ bin/console make:controller 

Choose a name for your controller class (e.g. TinyJellybeanController):
 > ToysController

 And now we have src/ToysController.php generated:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class ToysController extends AbstractController
{
    /**
     * @Route("/toys", name="toys")
     */
    public function index()
    {
        return $this->json([
            'message' => 'Welcome to your new controller!',
            'path' => 'src/Controller/ToysController.php',
        ]);
    }
}

Now that we have FOSRestBundle and other bundles are installed installed, let's make some simple changes to the controller and explain later:

<?php

namespace App\Controller;

use FOS\RestBundle\Controller\Annotations\View;

class ToysController
{
    /**
     * @View()
     */
    public function getToysAction()
    {
        $data = [
            'toy1Id' => [
                'name' => 'Plush Unicorn'
            ],
            'toy2Id' => [
                'name' => 'Toy car'
            ]
        ];

        return $data;
    }

    /**
     * @View()
     */
    public function postToysAction()
    {
        return ['success' => 1];
    }
}

You can se we have the following changes:

  • extends AbstractController is gone, because we are not rendering view like in a usual controller method
  • We are using @View annotation, which allows use to simply return data without rendering any view in a controller. So we can basically return an array or any other type of data and it will be transformed to the necessary format. It is done by the view response listener . It can be enabled by adding next lines to the fos_rest config: 
    view:
        view_response_listener:  true
  • You can see that action names getToysAction() and postToysAction() represent HTTP methods GET and POST, so you don't need manually to configure @Route(), like you would do in a normal Controller, because  FOSRestBundle this this for you automatically. 

One last thing to make this controller to work is we need to add some routing configuration to routes.yaml:

toys:
    type:     rest
    resource: App\Controller\ToysController

You can now access getToysAction() and postToysAction() via /toys (HTTP GET request) and /toys (HTTP POST request)

Summary

FOSRestBundle is a great bundle if you want to build RESTtful API, and it offers much more features and configuration, than we were able to cover in this simple example, which you can read about in the official Symfony documentation here.