Image for A quick guide to API Platform on Symfony

A quick guide to API Platform on Symfony

I'm currently doing #100DaysOfCode. If you read my last blog post you saw that I made a schedule for the coming days. I am already on day 22 so I've spent some time reviewing what I've done before moving onward. From here on out I'm going to depart from my schedule. Instead of going on to learn about express and Node.js, I'm focusing on a civics app. When that is done I'm going to continue learning new subject. But without further delay, let's get going!

Today we're going to build a simple API with the help of the PHP framework Symfony and the wonderful tool API Platform. To be able to follow along, make sure you meet the following requirements:


  • PHP 7.2.5 or higher

  • MySQL

  • Composer

  • Symfony



Here's a sneak peek of what's to come:


how to get an API going

Setup


I’m running this project on a Windows 10 machine. If you have another machine, then when downloading the required files use the files that suits your development environment.

I have MySQL being served through XAMPP, and also use the PHP binary found in this folder. Check out XAMPP at: www.apachefriends.org

Composer is the fantastic package manager in PHP. Find it at getcomposer.org

Symfony is the PHP framework for everything MVC. It starts small and expands with all the tools and functionality you need as your project grows. The Symfony command line interface (CLI) adds tools useful when developing a Symfony project. Install the Symfony CLI from symfony.com/download

Having PHP, MySQL, Composer and symfony ready, we are now ready to start development. With the CLI:s it’s easy to get started developing. Open a console (I’m going by this instead of terminal as I’m on Windows) and move into the directory where you want to have your project. The first command to run will create a Symfony skeleton project with a name you specify, I’m going by ‘smoothier’:
symfony new smoothier

When this command has run, we will move into the new project folder ‘smoothier’. Here we will get API Platform for our project. Let’s run this command:
composer require api

We now have the foundations for an API, but we also want entities to deal with in the API. Next we will get a tool that will make it easy to develop entities (more on what entities are below). Let’s run this in the console:
composer require maker --dev

Finally, there’s one more tool we need. It’s a tool for interpreting PHP classes to database tables. Let’s get it:
composer require migrations



Now there’s one more thing before we get to make our database entities. We’ll have to update our configurations so our tools will know where to find our database. Use your preferred editor and edit the file .env found at project root /smoothier/. Update the database url. Find the line where you have DATABASE_URL and edit it so you have the following (assuming you are running a standard local mysql):
DATABASE_URL=mysql://root:@127.0.0.1:3306/smoothier

Start your database engine if it’s not already started. I have XAMPP so I open it up and start MySQL.



Make entities


Entities are plain old PHP objects, but in API Platform they get a little more pizzazz. Entities are a logical structure for how they are to be stored in a database. Doctrine is the Object-Relational Mapper that interprets between a SQL-database and a PHP object. This means that the developer lets Doctrine handle most (if not all) of the SQL-commands.

If you want to know what databases are supported, check out the documentation at Doctrine Project: www.doctrine-project.org/projects/doctrine-dbal/en/2.10/reference/platforms.html

Before we begin making our entities, we should first sketch out what entities we need and how they relate to each other.

If you are new to relational databases check out this tutorial by Flavio: flaviocopes.com/relational-model/

In Smoothier we are all about getting you the right smoothie suggestion for every occasion. We’ll have Theme, Smoothie, and Image. Let’s write them up as they will be mapped by Doctrine:



Theme
name string
smoothie ManyToMany
image OneToMany

Smoothie
name string
themes ManyToMany
image OneToMany

Image
alt string
data BLOB
width integer
height integer
length integer
filetype string
theme ManyToOne
smoothie ManyToOne



A note on BLOB (Binary Large Object). A database is not usually structured to store image files (or files). It likes numbers and text. So before an image will be stored in our database we will convert it to a byte stream and store this in the database. This will also mean that any one fetching the images will have to convert them into their proper file formats.

Let’s start building these entities. Since this is PHP objects it could be done in an IDE, but we’re going to use the command line interface (CLI) we installed as maker.
Let’s start with the Image entity:
php bin/console make:entity

Give it a name: Image
On prompt if we want this as an API Resource: yes
Then we will add the fields we sketched out above. We do not need to add id, this will be added anyway.

alt
field type: string
field length: 255
nullable: no

data
field type: blob
nullable: no

width
field type: integer
nullable: no

height
field type: integer
nullable: no

length
field type: integer
nullable: no

filetype
field type: string
field length: 255
nullable: no

Exit maker by simply pressing enter when it’s prompting for another property.

Then let’s build the Theme entity:
php bin/console make:entity

Give it a name: Theme

When prompted if you want it as an API resource enter: yes
Then enter properties:
name
field type: string
field length: 255
nullable: no

image
field type: OneToMany
Class to be related: Image
New field inside Image: theme
nullable: yes

Then press enter to exit maker.

Then let’s build the Smoothie entity:
php bin/console make:entity

Give it a name: Smoothie
When prompted if you want it as an API resource enter: yes
name
field type: string
field length: 255
nullable: no

themes
field type: ManyToMany
Class to be related: Theme
New field inside Theme: smoothies
nullable: yes

image
field type: OneToMany
Class to be related: Image
New field inside Image: smoothie
nullable: yes

Press enter to exit maker.



That’s it for the entities. As this last entity was added, the missing properties in the other entities has been field in by the CLI. What’s next is to prepare our entities for storing in a database. To do this, run the following commands:
php bin/console doctrine:database:create
php bin/console make:migration
php bin/console doctrine:migrations:migrate

These commands will create a database with the name defined in the .env-file for the db-connection: smoothier. Next the entities will be analysed and doctrine will generate instructions for how the tables (database schema) should be configured. Lastly these instructions will be run on the database.

Finally this will leave us with four tables in the database. One for each entity, as well as one for the ManyToMany-relation between theme and smoothie.



Almost done


We can now check out the resulted api. But first we need to start the virtual server. Symfony comes with an excellent tool for this, so let’s run this at the project root: symfony serve

Now we can find the api at https://localhost:8000/api. The view will be as found at the top. As it presently stands, the API let us do anything.

Find the resulted code for this at github: github.com/femtearenan/smoothier



Epilogue


So what's up with storing an image?

I am familiar with two ways to store images that somehow involves databases. The first way is to store the image in a file structure. The database will then be used to keep track of the path to the image in this file structure. This is how I have set up this blog. The second way is to store the image in the database, as I have done for this overview of API Platform. But this comes with some challenges. This database is not a fan of images so we have to adapt to it. We are storing the images as BLOBs, which means that we will have to convert to BLOB and back from it. To know what we are converting back from BLOB, we are not just storing image data but image type as well. In PHP this process looks like this:


public function setFileAttributesWithImageFilePath($imagePath): self
{
$imgData = base64_encode(file_get_contents($imagePath));
$imgLength = filesize($imagePath);
$imgProps = getimagesize($imagePath);

$imgWidth = $imgProps[0];
$imgHeight = $imgProps[1];
$imgType = $imgProps["mime"];

$this->setData($imgData);
$this->setFiletype($imgType);
$this->setLength($imgLength);
$this->setWidth($imgWidth);
$this->setHeight($imgHeight);

return $this;
}



public function getParsedImageSrc()
{
return 'data:' . $this->getFiletype() . ';base64,' . $this->getData();
}



The first function takes a path to an image and gets the properties from it and sets it to the Image object. The second function returns the source-properties that can be used within an img-element. It contains file type and image data so it can be rendered in a view. We’re using base64 to encode the image, and use base64 again for decoding it in the view.

Now, this has been a quick guide to API Platform on Symfony. We covered how to setup a symfony skeleton project and add API Platform to it. We added entities with the help of the maker CLI and then had the CLI tool migrations handle the interpretation of it so we can store them in a database. API Platform is allowing anyone to get, put, delete whatever they like. This isn't ideal! There is no security! This is a topic I will leave for another time, but it is important to remember it.