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.
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:
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:
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).
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