Création d'une API REST sur Symfony

27 06 2017

5 commentaires

Création d'une API REST sur Symfony

Une API est conçue par des développeurs pour des développeurs. Le principe d'une API REST (Representational State Transfer) est de mettre à disposition des ressources à travers des url au format json ou xml. On met ainsi à disposition des url sur lesquelles un client Angular ou Symfony pourra venir effectuer des requêtes HTTP pour consommer cette API. Dans cette article nous allons voir comment créer une API REST avec Symfony.

Tout d'abord, il y a plusieurs niveaux pour définir une API REST. Les niveaux de conformité d'une API REST sont définis dans le modèle de maturité de Richardson.

  • niveau 0 : Le RPC sur HTTP en POX (Plain Old XML)
  • niveau 1 : L’utilisation de ressources différentiées
  • niveau 2 : L’utilisation des verbes HTTP
  • niveau 3 : L’utilisation des contrôles hypermédia

Une API qui répond aux 4 critères est dit pleinement REST ou Restful.

 

Utilité d'une API REST

L'utilité d'une API REST est de pouvoir lire des resources situées sur un serveur et de pouvoir les consommer depuis un autre serveur. L'échange de flux de données est ainsi qualifée de cross-domain. Pour cela nous aurons besoin de spécifier des entêtes spéciales pour autoriser un serveur à dialoguer avec un autre serveur. Car l'échange de flux de données cross-domain n'est pas autorisé par défaut. Pour cela nous aurons besoin de rajouter des entêtes spéciales de type CORS (Cross Origin Resource Sharing) avec notamment le control-access-allow-origin.

 

Configuration de Symfony

Pour créer une API REST avec Symfony, nous aurons besoin de 2 bundle:

  1. JMSSerializerBundle
  2. FOSRestBundle

JMSSerializerBundle va permettre de sérialiser les données au format json ou de les desérialiser en objet.

FOSRestBundle va permettre de simplifier la création de votre API REST grâce à une configuration spéciale de votre framework Symfony

Je n'expliquerai pas comment télécharger ces bundles, ni comment les activer. Pour cela consultez l'article Télécharger un bundle avec la commande require

Maintenant que ces 2 bundles ont été téléchargés et activés dans le appKernel.php, nous avons besoin de préciser dans le fichier config.yml la configuration de Symfony pour le bundle FOSRest:

fos_rest:
    param_fetcher_listener: true
    body_listener: true
    format_listener:
        rules:
            - { path: '^/api', priorities: ['json'], fallback_format: 'json' }
            - { path: '^/', priorities: ['html'], fallback_format: 'html' }
    view:
        view_response_listener: true
        formats:
            xml: true
            json : true
        templating_formats:
            html: true
        force_redirects:
            html: true
        failed_validation: HTTP_BAD_REQUEST
        default_engine: twig
    routing_loader:
        default_format: false
        include_format: false

 

Création d'une API REST

Nous allons maintenant créer notre controller placeController. Son rôle sera de pouvoir effectuer des actions sur des urls aux travers de verbes HTTP. Chaque action aura une méthode HTTP et une url qui lui sera propre. On pourra donc dire que notre API atteint le niveau 2 du modèle de maturité de Richardson.

Notre API va traité une entité Places qui contiendra 2 atrributs name et adress. Voici notre entité i:

<?php

namespace Blog\JournalBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Places
 * @ORM\Table(name="places", uniqueConstraints={@ORM\UniqueConstraint(name="places_name_unique",columns={"name"})})
 * @ORM\Entity(repositoryClass="Blog\JournalBundle\Repository\PlacesRepository")
 */
class Places
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="address", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $address;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Place
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set address
     *
     * @param string $address
     *
     * @return Place
     */
    public function setAddress($address)
    {
        $this->address = $address;

        return $this;
    }

    /**
     * Get address
     *
     * @return string
     */
    public function getAddress()
    {
        return $this->address;
    }
}

 

Et voici notre contrôleur placeController.php:

<?php
namespace Blog\JournalBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Blog\JournalBundle\Entity\Places;
use Blog\JournalBundle\Form\PlacesType;

class PlaceController extends Controller
{

    /**
     * @Rest\View()
     * @Rest\Get("/places")
     */
    public function getPlacesAction(Request $request)
    {
        $places = $this->get('doctrine.orm.entity_manager')
                ->getRepository('JournalBundle:Places')
                ->findAll();
        
    return $places;
    }

   /**
     * @Rest\View()
     * @Rest\Get("/places/{id}")
     */
    public function getPlaceAction(Request $request)
    {
        $place = $this->get('doctrine.orm.entity_manager')
                ->getRepository('JournalBundle:Places')
                ->find($request->get('id'));
        /* @var $place Place */

        if (empty($place)) {
            return new JsonResponse(['message' => 'Place not found'], Response::HTTP_NOT_FOUND);
        }

        return $place;
    }

    /**
     * @Rest\View(statusCode=Response::HTTP_CREATED)
     * @Rest\Post("/places")
     */
    public function postPlaceAction(Request $request)
    {
        $place = new Places();
        $form = $this->createForm(PlacesType::class, $place);

        $form->submit($request->request->all());

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->persist($place);
            $em->flush();
            return $place;
        } else {
            return $form;
        }
    }

     /**
     * @Rest\View(statusCode=Response::HTTP_NO_CONTENT)
     * @Rest\Delete("/places/{id}")
     */
    public function removePlaceAction(Request $request)
    {
        $em = $this->get('doctrine.orm.entity_manager');
        $place = $em->getRepository('JournalBundle:Places')
                    ->find($request->get('id'));
        /* @var $place Place */

        if ($place) {
            $em->remove($place);
            $em->flush();
        }
    }

    /**
     * @Rest\View()
     * @Rest\Put("/places/{id}")
     */
    public function updatePlaceAction(Request $request)
    {
        $em = $this->get('doctrine.orm.entity_manager');
        $place = $em->getRepository('JournalBundle:Places')
                    ->find($request->get('id'));

        if (empty($place)) {
            return new JsonResponse(['message' => 'Place not found'], Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(PlacesType::class, $place);

        $form->submit($request->request->all());

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->merge($place);
            $em->flush();
            return $place;
        } else {
            return $form;
        }
    }

    /**
     * @Rest\View()
     * @Rest\Patch("/places/{id}")
     */
    public function patchPlaceAction(Request $request)
    {
        $place = $this->get('doctrine.orm.entity_manager')
                ->getRepository('JournalBundle:Places')
                ->find($request->get('id'));

        if (empty($place)) {
            return new JsonResponse(['message' => 'Place not found'], Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(PlacesType::class, $place);

        $form->submit($request->request->all(), false);

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->merge($place);
            $em->flush();
            return $place;
        } else {
            return $form;
        }
    }
}

 

Notre API REST est à présent fonctionnelle. On va pouvoir tester notre API avec Postman. Puis nous pourrons consommer cette API avec un client comme Angular ou Symfony pour effectuer des requêtes dessus soit depuis le même serveur, soit depuis un autre serveur. Pour savoir comment faire vous pouvez lire notre article Consommer une API REST avec AngularJS.


 catégorie: Symfony


Commentaires

KelAncelo posté le 13/01/2019 à 14:56

Elimite <a href=http://genericvia.com>viagra prescription</a> Mail Order Macrobid Urinary Tract Infections Manyfacturing Amoxicillin <a href=http://buycial.com>cialis for sale</a> L Thyroxin Ohne Rezept Bestellen Viagra Farmacia Madrid Buy Tinidazole From India Online Cialis 10mg Nebenwirkungen <a href=http://gaprap.com>viagra</a> Amoxicillin And Teeth Amoxil Sur L' Forum Cialis Effets Secondaires


WilliamMic posté le 01/02/2019 à 17:14

cialis purchace on line fast no rx
is cialis by prescription only
<a href=https://kellyannehulme.com>cheap price</a>
pharmacy express belize cialis
cialis orosolubile
https://greatwinesgrandhouses.com
best price for cialis in usa
cialis 20 mg side effects
<a href=https://greatwinesgrandhouses.com>cheap price</a>
price of cialis without insurance
reputable cialis online
https://kellyannehulme.com


WilliamMic posté le 01/02/2019 à 18:55

buy cialis lilly
no prescription cialis online in canada
<a href=https://kellyannehulme.com>cialis</a>
generic cialis from us pharmacy
cialis from usa pharmacy
https://kellyannehulme.com
cialis 30 day free
cialis on line legal orders
<a href=https://kellyannehulme.com>Cheap cialis buy</a>
cialis generico vendita on line
cialis with out px
https://greatwinesgrandhouses.com


ArnoldRiz posté le 05/02/2019 à 09:39

generic cialis using mastercard
best price for cialis 5 mg 215
<a href="http://cialistlm.com">buy cialis</a>
bay cialis fast shipping
cialis e-shops europe
<a href="http://cialistlm.com">buy cialis</a>
best cheap cialis online
achat cialis generique
<a href="http://xcialisxx.com">Buy Cialis Online</a>


LesVomi posté le 19/02/2019 à 17:29

Prednisone Online Order Achat Cialis Andorre <a href=http://clanar.com>viagra</a> Viagra E Miopia Legally Levaquin Where To Buy Discount Overnight Shipping



Laisser un commentaire