4 min. read
Categories: Technical
API for a modern Symfony application
How to combine the logic provided by Sylius with your own custom subsystems or frontends? The answer is, of course, creating the right API - so that any developer will be able to use Sylius in any environment without any problems.

When developing a software used by thousands of people around the world, at some point you have to ask yourself how to help them combine the logic provided by Sylius with their own custom subsystems or frontends. The answer to this problem is, of course, creating the right API –  so that any developer will be able to use Sylius in any environment without any problems.

What are the solutions in Symfony API?

Keeping in mind the principle of never reinventing the wheel, after reviewing the Symfony API solutions (Sylius <heart> Symfony), we found the following two:

Both solutions approach API development in a different way. Thanks to the simple CRUD, we will show you the differences between them and answer which tool should be the first choice at the moment.

Let’s do CRUD

Moving on to what we like the most, let’s do CRUD (two even :)). We’ll start by preparing an entity to issue via the API:

Let’s create a new project:

symfony new ApiComparition

TIP : If you don’t have Symfony binary installed, you can read here https://symfony.com/download how to do it

We’re installing Doctrine:

composer require doctrine

And we’re preparing a simple `Book` entity with a few basic fields along with getters and setters:


/**
 * @ORM\Entity(repositoryClass=”App\Repository\BookRepository”)
 */
class Book implements BookInterface
{
   /**
    * @ORM\Id()
    * @ORM\GeneratedValue()
    * @ORM\Column(type=”integer”)
    */
   private $id;

   /**
    * @ORM\Column(type=”string”, length=255)
    */
   private $title;

   /**
    * @ORM\Column(type=”string”, length=255)
    */
   private $type;

   /**
    * @ORM\Column(type=”integer”, nullable=true)
    */
   private $length;

   /**
    * @ORM\Column(type=”string”, length=255, nullable=true)
    */
   private $author;

   public function getId(): ?int
   {
       return$this->id;
   }

   public function getTitle(): ?string
   {
       return$this->title;
   }

   public function setTitle(string $title): void
   {
       $this->title = $title;
   }

   public function getType(): ?string
   {
       return$this->type;
   }

   public function setType(string $type): void
   {
       $this->type = $type;
   }

   public function getLength(): ?int
   {
       return$this->length;
   }

   public function setLength(?int $length): void
   {
       $this->length = $length;
   }

   public function getAuthor(): ?string
   {
       return$this->author;
   }

   public function setAuthor(?string $author): void
   {
       $this->author = $author;
   }

First, API Platform.
By using the benefits of Symfony Flex, simply type in the console:

composer require api

Now we can create our own API resources.
The API Platform allows you to configure the resource in three ways:

  • annotations, 
  • XML
  • Yaml

In this example we will show configurations for annotations (as suggested by the API Platform)

We can register our Book as API Resource:


use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ApiResource()
 * @ORM\Entity(repositoryClass=”App\Repository\BookRepository”)
 */
class Book implements BookInterface
{

And with this simple annotation we have created a fully functional CRUD

The great advantage of API Platform is also the built-in documentation generator (swagger) which presents our entity like this:

API Platform  enabled the creation of a basic Crud in a few minutes.
Now we will achieve the same effect through the FOSRest Bundle.

We install  FOSRest bundle:

composer require friendsofsymfony/rest-bundle

First, a little initial configuration:

Our requests and responses will be in json format


#config/packages/fost_rest.yaml
fos_rest:
  view:
      view_response_listener:  true
  format_listener:
      rules:
          – { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json ] }

We will configure API in annotations


#config/routes/annotations.yaml
rest_controller:
  resource: ../../src/Controller/Api/
  type: annotation
  prefix: /api

We pass to the coding of our API

We’re creating a controller to support our entity


declare(strict_types=1);

namespace App\Controller\Api;

use App\Entity\Book;
use App\Entity\BookInterface;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\ORM\EntityManagerInterface;
use FOS\RestBundle\Controller\AbstractFOSRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

final class BookController extends AbstractFOSRestController
{
    /** @var EntityManagerInterface */
    private $entityManager;

    /** @var ObjectRepository */
    private $objectRepository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
        $this->objectRepository = $this->entityManager->getRepository(Book::class);
    }

    /**
     * @Rest\Post(“/books”)
     */
    public function postBook(Request $request): View
    {
        $book = new Book();
        $book->setTitle($request->get(‘title’));
        $book->setAuthor($request->get(‘author’));
        $book->setLength($request->get(‘length’));

        $this->entityManager->persist($book);
        $this->entityManager->flush();

        return View::create($book, Response::HTTP_CREATED);
    }

    /**
     * @Rest\Get(“/books/{id}”)
     */
    public function getBook(int $id): View
    {
        $book = $this->objectRepository->find($id);

        return View::create($book, Response::HTTP_OK);
    }

    /**
     * @Rest\Get(“/books”)
     */
    public function getBooks(): View
    {
        $books = $this->objectRepository->findAll();

        return View::create($books, Response::HTTP_OK);
    }

    /**
     * @Rest\Put(“/books/{id}”)
     */
    public function putBook(int $id, Request $request): View
    {
        /** @var BookInterface $book */
        $book = $this->objectRepository->find($id);

        $book->setTitle($request->get(‘title’));

        $this->entityManager->persist($book);
        $this->entityManager->flush();

        return View::create($book, Response::HTTP_OK);
    }

    /**
     * @Rest\Delete(“/books”)
     */
    public function deleteBook(int $id): View
    {
        $this->entityManager->remove($this->objectRepository->find($id));
        $this->entityManager->flush();

        return View::create(Response::HTTP_OK);
    }
}

Thanks to that, we’ve got our Crud API:

What’s the difference between API Platform and FOSRestBundle?

As you could see in this simple example, API Platform and FOSRestBundle allow you to create API in two  completely different ways. The first one focuses on configuration, the second one on manually creating functionality. Configuring one simple entity in both cases did not cause any problems. But when creating a real application with dozens of entities the amount of code needed to create API by FOSRest bundle would be huge compared to the configuration of API Platform. The simplicity of work on API offered by API Platform significantly displaced FOSRestBundle for us. In the end, as the creator of Symfony said: “API Platform is the most advanced API platform, in any framework or language”

If we pay attention to the disadvantages of API Platform, it is worth highlighting that a lot of logic happens outside of our control. Of course, many aspects can be configured but not everything will be legible (especially for developers who are just starting their work with API Platform).

So, what’s the best way to create an API?

To sum up, if you want to create an API, we recommend that you first check out the API Platform, but if you are looking for a tool in which you design every functionality yourself, FOSRestBundle will work well as a low-level dependency.

Helpful links:

API Platfom – https://github.com/AdamKasp/Basic-CRUD-with-API-Platform

FosRest bundle –https://github.com/AdamKasp/basic-crud-with-fosrest-bundle

Share:
More from our blog
Technical 4 min read 04.12.2024
Here’s everything you had to know about the first major release since 2017! Over 7 years after the first major release, on Nov 12, 2024, we have released Sylius 2.0.0. We had a great opportunity to announce it first at SyliusCon in Lyon, but now, as we are back to… Read More
4 min read 22.11.2024
The emotions start to settle after SyliusCon, and it’s time to reflect on this incredible milestone in our journey. Why a milestone? Because SyliusCon exceeded our expectations in every possible way. We broke attendance records and brought together the key figures of our community, numerous partners, freelancers, and simply all… Read More
Cloud 4 min read 17.06.2024
We are thrilled to announce that we just signed a strategic partnership with Platform.sh, and as a result, we are extending our offer with Sylius Cloud powered by Platform.sh. Platform.sh is a modern Platform-as-a-Service (PaaS) solution that allows businesses to leverage the cloud environment without losing access to the code… Read More
Comments