Make a rest api with symfony 3

Hello,

As a symfony freelance, We still need to interface our sites with others. To do this we often use API (Applications Programming Interface).

From lasts posts, We explained to you what is a API and the two main methods to develop them in PHP : REST et SOAP.

Here we go further by showing you how to create a REST API with PHP and framework Symfony 3 !!!

To get to the simplest, we assume that you have a web server properly configured with Composer installed et fonctionnal.

To start, you need to install the Symfony framework:

# From you appache root directory or vhost.
composer create-project symfony/framework-standard-edition example "3.3.*"

This command line will be used to download and install the framework in the example directory.

Then we will use two bundles essential to our application :

composer require jms/serializer-bundle 
composer require friendsofsymfony/rest-bundle

We need to create our own bundle :

cd example
php bin/console generate:bundle
php bin/console doctrine:create:database

We imagine making this entity on this API :

# src/ExampleBundle/Resources/config/doctrine/weenesta_user.orm.yml
ExampleBundle\Entity\WeenestaUser:
    type: entity
    table: weenesta_user
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        name:
            type: string
            length: 100

Your own Bundle is configured to use the FOS Rest bundle :

#app/config/config.yml
fos_rest:
    format_listener:
        rules:
            - { path: '^/weenestauser', priorities: ['xml', 'json'], fallback_format: xml, prefer_extension: true }
            - { path: '^/', priorities: [ 'text/html', '*/*'], fallback_format: html, prefer_extension: true }

We generates the entity from doctrine :

php bin/console doctrine:generate:entity WeenestaUser
php bin/console doctrine:schema:update --force

We creates controller :

#src/ExampleBundle/Controller/WeenestaUserController.php

namespace ExampleBundle\Controller;

use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;

use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\Delete;

use ExampleBundle\Entity\WeenestaUser;

class WeenestaUserController extends FOSRestController
{
    /**
     * findWeenestaUserByRequest
     * 
     * @param Request $request
     * @return WeenestaUser
     * @throws NotFoundException
     */
    private function findWeenestaUserByRequest(Request $request) {

        $id = $request->get('id');
        $user = $this->getDoctrine()->getManager()->getRepository("ExampleBundle:WeenestaUser")->findOneBy(array('id' => $id));

        return $user;
    }

    /**
     * validateAndPersistEntity
     * 
     * @param WeenestaUser $user
     * @param Boolean $delete
     * @return View the view
     */
    private function validateAndPersistEntity(WeenestaUser $user, $delete = false) {

        $template = "ExampleBundle:WeenestaUser:example.html.twig";

        $validator = $this->get('validator');
        $errors_list = $validator->validate($user); 

        if (0 === count($errors_list)) {

            $em = $this->getDoctrine()->getManager();

            if ($delete === true) {
                $em->remove($user);
            } else {
                $em->persist($user);
            }

            $em->flush();

            $view = $this->view($user)
                         ->setTemplateVar('user')
                         ->setTemplate($template);
        } else {

            $errors = "";
            foreach ($errors_list as $error) {
                $errors .= (string) $error->getMessage();  
            }

            $view = $this->view($errors)
                         ->setTemplateVar('errors')
                         ->setTemplate($template);

        } 

        return $view;
    }

    /**
     * newWeenestaUserAction
     * 
     * @Get("/weenestauser/new/{name}")
     * 
     * @param Request $request
     * @return String
     */
    public function newWeenestaUserAction(Request $request)
    {   
        $user = new WeenestaUser();
        $user->setName($request->get('name'));

        $view = $this->validateAndPersistEntity($user);

        return $this->handleView($view);
    }

    /**
     * editWeenestaUserAction
     * 
     * @Get("/weenestauser/edit/{id}/{name}")
     * 
     * @param Request $request
     * @return type
     */
    public function editWeenestaUserAction(Request $request) {

        $user = $this->findWeenestaUserByRequest($request);

        if (! $user) {
            $view = $this->view("No WeenestaUser found for this id:". $request->get('id'), 404);
            return $this->handleView($view);
        }

        $user->setName($request->get('name'));

        $view = $this->validateAndPersistEntity($user);

        return $this->handleView($view);
    }

    /**
     * deleteWeenestaUserAction
     * 
     * @Get("/weenestauser/delete/{id}")
     * 
     * @param Request $request
     * @return type
     */
    public function deleteWeenestaUserAction(Request $request) {

        $user = $this->findWeenestaUserByRequest($request);

        if (! $user) {
            $view = $this->view("No WeenestaUser found for this id:". $request->get('id'), 404);
            return $this->handleView();
        }

        $view = $this->validateAndPersistEntity($user, true);

        return $this->handleView($view);
    }

    /**
     * getWeenestaUserAction
     * 
     * @Get("/sweenestausers")
     * 
     * @param Request $request
     * @return type
     */
    public function getWeenestaUserAction(Request $request) {

        $template = "ExampleBundle:WeenestaUser:example.html.twig";

        $users = $this->getDoctrine()->getManager()->getRepository("ExampleBundle:WeenestaUser")->findAll();

        if (0 === count($users)) {
            $view = $this->view("No WeenestaUser found.", 404);
            return $this->handleView();
        }

        $view = $this->view($users)
                     ->setTemplateVar('users')
                     ->setTemplate($template);

        return $this->handleView($view);
    }
}

We create Twig template :

#src/ExampleBundle/Resources/views/WeenestaUser.html.twig
{% if errors is defined %}
  {{ errors }}  
{% else %}
  {% if users is defined %}
    {{ users | serialize }}
  {% else %}
    {{ user | serialize }}
  {% endif %}
{% endif %}

And voila, you have created your first API with symfony framework !

You can get full source code from GitHub.

Your can access it from your web server...

See you soon,

Mathieu