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:
Adam Kasperczak
Graduate of financial studies, interested and recently employed in programming. In free time: board games enthusiast who also likes to watch a good movie and sip some tasty wine.
More from our blog
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
Technical 4 min read 11.06.2024
Abstract 1.12 released in Q4 2022 1.13 on Apr 23rd, 2024 (a year later than we anticipated while releasing 1.12) 3859 commits 23 contributors A stabilized Sylius API powered by API Platform It’s been a long and bumpy road. Having it behind our backs was a highway that led Sylius… Read More
Business Ecosystem News 4 min read 06.06.2024
Welcome to the May summary! As an open-source eCommerce framework, Sylius continues to evolve with significant contributions from our vibrant community and valuable product updates. Apart from describing the technical changes, we will also quickly summarize the Sylius Technical Fundamentals & Sylius Polish Community Meetup and eCommerce Day Kaunas, as… Read More
Comments