Back to all blogposts

How to build an API? A Developer’s Guide to API Platform 1/2

Piotr Brzezina

Piotr Brzezina

Senior PHP Developer

In the article, I’ll present how to build an API in a swift and simple way, using Symfony and API Platform. This library provides a fully-working CRUD, pagination, validation, HATEOAS and documentation. It supports XML, JSON and JSON-LD formats. Thanks to the use of markers – it also supports SEO. Moreover, it enables using GraphQL. Below, I’ll show you how API Platform works on an example of a simple application.

Our application’s name is “Flashcards” and it helps to learn new words. Whilst building the app, I’ll be showing you, step by step, the following API Platform components:

  •  creation of a simple CRUD,
  •  serialization groups,
  •  validation,
  •  enabling/disabling Operations,
  •  its own Operations,
  •  nested endpoints,
  •  searching.

Description of the application

The app should allow users to have a variety of subjects they want to learn. Each subject needs to be divided into lessons. Users can add flashcards with questions and answers to each lesson. They should have access to the resources which are created by them only. And flashcards’ search should be possible through questions and answers.


The easiest (and probably the best) way for developers to start working with API Platform is downloading a ready-made pack from GitHub. It contains all the necessary components you need to create the first project. There is a docker configuration inside the pack. After extracting the content and launching it through the command docker-compose up -d the complete development environment will be started. It contains the following elements:

  •  php – a container with PHP 7.2 and the composer,
  •  db – a container with PostgreSQL (port 5432) database,
  • client – a container with a frontend part of the app; on default it contains a welcome page (port 80),
API Platform welcome page
API Platform welcome page
  • admin – a container with the administration panel; it’s created automatically thanks to the API AutoDiscovery (port 81),
    There is an admin panel in API Platform
  • API – a container with API and its documentation,
    API Platform helps generating documentation
  • cache-proxy – a container with a proxy (Varnish) for API (port 8081),
  • h2-proxy – http/2 and https for all the apps (ports: 443 – client, 444 – admin, 8443 – API and 8444 – cache-proxy); it should be used for development purposes only.

If you don’t need the complete environment from the pack – you can use an alternative installation option. It uses Symfony Flex and Composer. You’ll find all the details about the process on the documentation website.


We’ll start by creating classes, which will represent each of the application elements. Then, we’ll map these classes on the database and we’ll use the annotation provided by Doctrine ORM.

Let’s start with the user model. It will consist of basic information about the user: name and email. In the later stage, we’ll add the authentication. That’s why it’s worth making sure that a model implements UserInterface and contains all the necessary fields.

Then, we’ll prepare a model for subjects. According to the specification, a model should have information about the subject’s owner, its name and a list of added lessons.

Next, we’re creating a model for a lesson. It should contain information about what subject the lesson relates to, what is the subject and additionally, information about flashcards included.

The last element is a model of a flashcard. It should contain a question, an answer and information about what lesson the flashcard relates to.

Once the models are ready, it’s time to update the database schema.

bin/console doctrine:schema:update –force


In order to create endpoints – it’s necessary to inform API Platform library which models should be considered as API elements. It’s possible to do it with XML, yaml or annotation. I decided to use the last method. For classes: User, Subject, Lesson, Flashcard, you should add annotation @ApiResource().

Here’s an example of Flashcard class:

You can find the examples of the other classes by clicking in the following links: Lesson, Subject and User.

The basic API version is now ready. You can perform simple operations on models: adding, reading, modifying and deleting. Additionally, the API Platform automatically generated the documentation.

Documentation is created automatically in API Platform

Serialization groups

Generated endpoints are not adapted to our needs yet. They require precise information about the fields which will be inputted and presented.

Whilst normalization/denormalization, API Platform uses symfony/serializer. Thanks to that, it’s possible to use Group attribute. With that being used, you can change the form of objects’ presentation.

In this case, we’ll be using an annotation @Group to set serialization groups. Alternatively, you can use yaml or XML formats. More details about the serialization process are on the component documentation.

When creating a new subject, the only field which should be provided by the user is the name. Whilst downloading data about the subjects, information about the identification and previously inputted name should be displayed.

To achieve that, we need to add a group subjectList to the fields id and name. It will be used when downloading information about an object. To the field name, we need to add a group subjectCreate. Thanks to that, it’ll be possible to define if a field should be inputted when creating a new subject.

Next, it’s necessary to configure the API Platform by setting properties normalizationContext and denormalizationContext for suitable values. Property normalizationContext is responsible for informing which groups should be taken when changing the object into the array. denormalizationContext property is responsible for a reverse process.

We act similarly with all the remaining models: Flashcard, Lesson and User.

As the documentation is created automatically, it’s always up to date. After adding @Group annotation, documentation is updated automatically and it contains information about the used files only.

Document is updated automatically

In the next part of the article, I’ll focus on more advanced cases of using serialization groups. I’ll recommend reading the documentation of this element on a website.


The application starts taking its shape. But it’s still very unstable, unfortunately. If you provide incorrect values when creating new registries – the application will return an error, instead of letting us know that the value is incorrect.

API Platform comes ahead of this issue and it allows using a symfony/validator component. To use it, you need to write certain constraints to the objects’ properties. You can do it through yaml, XML or php. Similarly to the previous examples, I’ve used annotation. To read more about validator itself, it’s worth visiting a documentation website.

We’re adding constraints to the models, to make sure we’ll be unable to add the data which may cause a breakdown of an application.

We act similarly with all the remaining ones: Lesson, Subject and User.

After adding constraints, the application will stop returning errors. Instead, it’ll start coming with standardised information about the fields with incorrect data.

You can create resources using API Platform

Moreover, the documentation has been expanded with information about the required fields. API Platform allows operating on more complex examples. For example, it allows setting different serialization groups, depending on an action performed. It also allows setting dynamic serialization groups. Again, I’ll recommend reading through the documentation for more detailed info.

See also: What are the Google Maps API alternatives?


Configuration of available actions

It happens, that we don’t need automatically generated endpoints or that we need to add a special endpoint. API Platform allows us managing available endpoints in a simple way. By default, for all the resources there are 5 basic endpoints created. They are grouped into two types of operations. The first group is about operations performed on a collection of objects or creating a new element. Another type of operations is always related to a certain element (and it’s necessary to indicate this element).

In our app, the user can’t delete previously added lessons and subjects. That’s why, in these two cases, it’s indispensable to describe all the available actions. We’ll leave all the actions besides delete.

At the time being, we limited ourselves to deleting redundant actions. Now, it’s time for our own action. Our API should allow the user to change the password. We want to create the following URL: /users/{id}/change-password. And the user should provide only their new password. To achieve that, we don’t need to write a new action in a controller. It’s as simple as creating a new operation in API Platform and informing it that for a certain operation, the denormalization group should have a value that is only one field that may be provided with a new password. It’s necessary to take care of a password to be strong enough. We can achieve that by using validation.

We’ve added a new operation changePassword. We set a new denormalization group for it and a validation group userChangePassword. To make sure that the remaining validations still work, it’s necessary to set a default validation group in validationGroups properties. In this case, its name is userCreate. The remaining thing is to modify properties in the User class to make sure it has proper validation and serialization groups.

The new endpoint works already. API Documentation has been automatically updated.

Nested links

API should let user getting lessons which belong to a certain subject and to flashcards which belong to a certain lesson. API Platform allows preparing endpoints quickly and these will come with necessary data. It’s only about marking relations to lessons and flashcards with the parameter ApiSubresource.

Thanks to these modifications, we got 2 new endpoints. Again, API documentation has been modified automatically.

You can create resources using API Platform

For more details about managing operations in the API Platform, I’ll recommend reading documentation of the library.


Data searching is one of the most often repeated business requirements. Our application should let the user search for flashcards through fields question and answer. API Platform prepared a collection of filters that you can use.

There are several filters available:

  • search filter: enables searching through strings (exact, partial, starting with a certain phrase or word),
  • date filter: enables searching through a date (or before/after a date),
  • boolean filter: enables searching through boolean fields,
  • range filter: enables searching through numbers (higher, lower, in between),
  • exits filter: enables searching if a field has any value (if it’s not “null”),
  • order filter: enables sorting a list of results through a provided field.

Besides built-in filters, there is a possibility to add your own ones. Flashcards must have the ability to be searched through text. To do this, we will use a search filter (SearchFilter::class). But, to make the search not exact, we will use parameter partial. It’ll mean that we will be looking for any text with the given phrase (LIKE %searchPhrase%). We know which filter we want to use, but how to inform API Platform about it? As always, we can do it by using one of a few methods – through XML, yml or annotations. As earlier, I’ll use annotation. We add a new annotation @ApiFilter to the Flashcard model.

After adding it, we will receive a possibility to search through fields question and answer and documentation are updated with this information.

After adding all the necessary info, you can search through questions and answers in the app

Detailed information about the implementation of the remaining filters is available on the website.

See also: Creating an API with Apiary


I’ve presented how to build an API and showed some of the basic functionalities of API so far. It’s possible to create new flashcards, lessons, subjects and new users in the app. Endpoints will come up with the necessary data. Thanks to validation, the application will be stable. But still, it lacks some necessary elements. This is a subject for another piece – I will introduce it in the second part of the API Platform guide.

The application built for article purposes can be found here.

You may also like

What would you like to do?

    This site is protected by reCAPTCHA and the Google
    Privacy Policy and Terms of Service apply.

    We regard the TSH team as co-founders in our business. The entire team from The Software House has invested an incredible amount of time to truly understand our business, our users and their needs.

    Eyass Shakrah

    Co-Founder of Pet Media Group


    Thank you for your inquiry!

    We'll be back to you shortly to discuss your needs in more detail.