Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Installing API Platform

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Hello and welcome you beautiful people, to a tutorial that's near and dear to my heart: how to build magnificent castles with Legos. Oh, that would be awesome, wouldn't it? But really, we're here to talk about API Platform Version 3, which I promise is as fun as playing with Legos. Just don't tell my son I said that.

API Platform is, very simply, a tool on top of Symfony that allows us to build powerful APIs and love the process! It's been around for years and, honestly, it's crushing it. They have their own dedicated conference and, they've really outdone themselves with the latest version 3.

If you're new to API Platform, I wouldn't blame you if you said:

Come on Ryan... creating an API isn't that hard. It's just returning JSON: a bunch of squigglies and brackets!

Ok, that is true (at least for the first few endpoints). But wow are there a lot of little details to keep track of. For example, if you have an API that returns product data, you'll want that product JSON to be returned in the same way with the same fields, across all endpoints. That process is called serialization. On top of that, a lot of APIs now return extra fields that describes what the data means. We're going to see and talk about something called "JSON-LD", which does exactly that.

What else? How about documentation? Ideally interactive documentation that's generated automatically... because we do not want to build and maintain that by hand. Even if you're building an API just for yourself, having documentation is awesome. Paginating collections is also super important, filtering and searching collections, validation and content-type negotiation, which is where that same product could be returned as JSON, CSV, or another format. So yes, creating an API endpoint is easy. But creating a rich API is another thing entirely. And that's the point of API Platform. Oh, and if you're familiar with API Platform Version 2, version 3 will feel very familiar. It's just cleaner, more modern, and more powerful. So get out your Legos, and let's do this!

The API Platform Distribution

There are two ways to install API Platform. If you find their site and click into the documentation, you'll see them talk about the API Platform "Distribution". This is pretty cool! It's a completely pre-made project with Docker that gives you a place to build your API with Symfony, a React admin area, scaffolding to create a Next.js frontend and more. Heck, it even gives you a production-ready web server with extra tools like Mercure for real-time updates. It's the most powerful way to use API Platform.

But... in this tutorial, we're not going to use it. I hate nice things! No, we'll start our Lego project from scratch: with a perfectly normal and boring Symfony app. Why? Because I want you to see exactly how everything works under the hood. Then, if you want to use this Distribution later on, you totally can.

Project Setup & Our Project

Okay, to be a true "API Platform JSON Returning Champion", you should code along with me! Download the source code from this page. And after unzipping it, you'll find a start/ directory with the same code that you see here. This is a brand new Symfony 6.2 project with... absolutely nothing in it. Open up this README.md file for all the setup instructions. The last step will be to open the project in a terminal and use the Symfony binary to run:

symfony serve -d

This starts a local web server at I'll cheat and click that link to open up... a completely empty Symfony 6.2 project. There's literally nothing here except for this demo homepage.

What are we going to build? As we all know, the internet is missing something terribly important: an application for dragons to boast about their stolen treasures! Because if there's one thing a dragon likes more than treasure, it's bragging about it. Yup, we'll create a rich API that lets tech savvy dragons post new treasures, fetch treasures, search treasures from other dragons, etc. And yes, I did just finish reading the Hobbit.

Installing API Platform

So, let's get API Platform installed! Spin back over to your terminal and run:

composer require api

This is a Symfony Flex alias. Up here, you can see it's actually installing something called api-platform/api-pack. If you're not familiar, a "pack" in Symfony is, kind of a fake package, that allows you to easily install a set of packages. If you scroll down, it installed api-platform itself, Doctrine, since I didn't already have that, and some other packages. At the bottom... let's see... the doctrine-bundle recipe is asking us if we want to include a docker-compose.yml file to help add a database to our project. How nice of it! This is optional, but I'm going to say "p" for "Yes permanently". And... done!

The first thing to see is in the composer.json file:

85 lines composer.json
... lines 2 - 5
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^3.0",
"doctrine/annotations": "^1.0",
"doctrine/doctrine-bundle": "^2.8",
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.14",
"nelmio/cors-bundle": "^2.2",
"phpdocumentor/reflection-docblock": "^5.3",
"phpstan/phpdoc-parser": "^1.15",
"symfony/asset": "6.2.*",
"symfony/console": "6.2.*",
"symfony/dotenv": "6.2.*",
"symfony/expression-language": "6.2.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "6.2.*",
"symfony/property-access": "6.2.*",
"symfony/property-info": "6.2.*",
"symfony/runtime": "6.2.*",
"symfony/security-bundle": "6.2.*",
"symfony/serializer": "6.2.*",
"symfony/twig-bundle": "6.2.*",
"symfony/validator": "6.2.*",
"symfony/yaml": "6.2.*"
... lines 33 - 83

As promised, that API Platform pack added a bunch of packages into our project. Technically, these aren't all required, but this is going to give us a really rich experience building our API. And if you run

git status

... yep! It updated the usual files... and also added a bunch of config files for the new packages. It looks like there's a lot... but looks can be deceiving. All of these directories are empty... and the config files are small and simple. We also have some docker-compose files that we'll use in a minute to spin up a database.

So... now that API Platform is installed... did that give us anything yet? It did! And it's cool! Go back to the browser and head to /api. Whoa! We have an API documentation page! It's empty because we don't, ya know, actually have an API just yet, but this is going to come to life very soon.

Next: Let's create our first Doctrine entity and "expose" that as an API Resource. It's time for some magic.

Leave a comment!

Login or Register to join the conversation
ties8 Avatar

I have not yet completed the course, so maybe i missed it
In the old course for API Platform 2, the creation of a Resource Metadata Factory was discussed. Since it is a very convenient way to create Metadata for inheritance structures (Bleu de Gex extends Blue Cheese extends Cheese) i would like to keep it after my migration to API Platform 3 and Symfony 6.
Is a video on the creation of the new or a replacement for the Resource Metadata Factory planned? Or generally, is the use of that approach even recommended with api platform 3?


Hey @ties8

In our recent ApiPlatform 3 tutorial we do not talk too much about customizing the docs but I think this video may help you out https://symfonycasts.com/screencast/api-platform-security/open-api-decoration
You can also check the ApiPlatform docs


ties8 Avatar

I am not sure if we are on the same page about what can be done with the Resource Metadata Factory in 2.6. Perhaps i should explain a bit further.
As far as i understood it, the Resource Metadata Factory generates the default values for what can then be modified inside the #[ApiResource] attribute set on every class.
So in 2.6 by decorating the Resource Metadata Factory i could once, dynamically, change the options which would normally be statically defined in every class inside the #[ApiResource] attribute. In your course "API Platform 2 Chapter 27" the system is used to dynamically set the normalization context instead of having to define it statically in the API Platform attribute on every class.
You can modify the CollectionOperations, ItemOperations, SubresourceOperations and other Attributes of the resource.
In my example of a inheritance structure i would have to define an #[ApiResource(...)] with the same content: short name, security ect. on every class which inherits from "Cheese". With a Resource Metadata Factory i avoid having to do that 3 times but can centralize it. The decorated Resource Metadata Factory checks if the resource it generates the metadata for is inheriting "Cheese" and then adjusts the data it generates accordingly.

I hope its now clear what i used the Metadata Factory for, if there is a video already available or in planning on how the stuff the Decorated Metadata Factory did is now done i would appreciate it if you could let me know.


Hey @ties8!

Yup, I know what you're talking about :). The short answer is that no, unfortunately, I decided not to cover this for the API Platform 3 tutorial. I just wasn't sure how many people were actually using it. But I can also say that, afaik, there is nothing that makes this now a "bad idea" in API Platform 3. The approach just needs to be updated for the config system. I can't say how to do it, as I haven't tried it. However, I don't think that the solution would be all that different. API Platform 3 still has this concept of "resource metadata collection factories" - here's the interface https://github.com/api-platform/core/blob/main/src/Metadata/Resource/Factory/ResourceMetadataCollectionFactoryInterface.php - and there are a bunch of them that use decoration to add more data. And you'll notice that interface looks identical to what we did in API Platform 2. So, this may just be a matter of adjusting your old interfaces and a few minor tweaks.

Btw, if you're successful (or not), I'd love to know!


ties8 Avatar

Starting my migration i found using "DoctrineOrmResourceCollectionMetadataFactory" was a good way to start. So far it seems to work, although i have not yet migrated my tests to v3.
As for using the Metadata Factory, first i use it for inheritance, one Metadata Factory sets all metadata for every child Resource and second for mass applying security to a part of an app. For example if i have 5 Resources only accessible to Premium Subscribers i can create and apply a "PremiumSubscriberResourceInterface" to all five of them and handle security centralized inside the Metadata Factory.


Woo! Sounds promising. And your use-case makes a lot of sense. This is one of those features where it feels like they probably shouldn't add something so automatic to the core of API Platform... but for certain projects, users can really leverage it.

Good luck!

CanadaGuy Avatar
CanadaGuy Avatar CanadaGuy | posted 3 months ago | edited

I followed the demo instructions but without downloading the zip file that starts the project...

The demo won't work... I think its because the "src/Controller" folder is still empty when you just run the following:
composer create-project symfony/skeleton:"6.2.*" test
cd test
composer require api
composer require webonyx/graphql-php
composer require maker --dev

During the playback of the cast, I noticed there are 2 files in the Controller folder when you open and close the folder really quick, but there's no way to know what to put in those files.

My project only shows the simple "Welcome to Symfony 6.2.6" page, but adding /api to my URL gets me a 404 Not found. However running "bin/console debug:router" shows I am on the right path to getting something because the path names and info show up for "api_entrypoint", "api_doc", etc. but all those URLS get me a NOT FOUND.

Is there some key to the base "Controller" file that needs to be present that was skipped in the otherwise very nice tutorial?


Hey there,

I believe you're missing a few required packages that are absent from the symfony/skeleton project. Try creating a new project but installing symfony/webapp-pack


CanadaGuy Avatar

Thanks for the tip... That helped, but still had a problem, which in the end turned out to be a needed ".htaccess" file in the "public" folder (Running XAMPP on Windows) so it would perform the needed mod-rewrite rules forcing routes like /api to be directed into the index.php file instead of directly to apache (which of course could not find a /api folder under the public folder


Ohh, you're using XAMPP, I assumed you were using Symfony's web server. It does what you said under the hood :)

Michal-K Avatar
Michal-K Avatar Michal-K | posted 4 months ago | edited

Hi! I have a question. Will this course work well with Symfony 5? :D
I mean, will it work the same as if it had Symfony 5? :D


Hey Michal!

Hmm. The problem is that API Platform 3 requires Symfony 6. So if you're using API Platform with Symfony 5, then I think you're using version 2.7, not 3. However, 2.7 and 3.0 are identical, except that deprecated items have been removed in 3.0. And, if you're using 2.7, you should set the metadata_backward_compatibility_layer flag to false - ref https://api-platform.com/docs/core/upgrade-guide/#im-migrating-from-26-and-want-to-prepare-for-30

If you do that, then yes, I think we very few exceptions, the tutorial will work fine for Symfony 5 and API Platform 2.7. If you hit any snags, you can let us know and we'll do our best to help!


1 Reply
vishajr Avatar

Hi Ryan, I just jumped into API Platform and it's pretty confusing to me.

I am planning to go through the API Platform 2 first since it has the security related content.

Is it okay or shall I just wait for API Platform 3 and start from there? Thanks!


Hey Vishajr,

The more you watch - the more you know ;) So, feel free to jump into ApiPlatform v2 tutorials first if you need it now, because releasing same tutorials on v3 will take some time. So it makes sense to start from those tutorials that are already recorded if you don't want to simply wait for new ones. But later, when v3 tutorials will be released - you can watch it again and I bet you will discover more new things for yourself, or even better understand it because you will have some base after old tutorials :)

Also, we added some notes in our v2 tutorials mentioning some differences and BC breaks, so it should help you as well ;)


kyotomano Avatar
kyotomano Avatar kyotomano | posted 4 months ago

Hi! Is this course going to be divided into 3 parts just like api platform 2? [base, security, custom resources]. I also have more questions. Are you going to cover Mercure? When are you going to release all 3 parts (I read comment from SC team member who claimed that it would be released by the end of the year, but it was 3 months ago)? Btw. Great pick. V3 seems to be much different than V2


Hi kyotomano!

This is a perfect time to ask these questions :).

Is this course going to be divided into 3 parts just like api platform 2? [base, security, custom resources].

Probably, yes. Though there are a few things that I need to look into - like much better support in API Platform 3 for DTO objects - that might affect exactly what's in each episode or how we split it all up.

Are you going to cover Mercure?

I wasn't planning on it... at least not in any big way. But is that something you're interested with in regards to API Platform? What are you hoping to use it for?

When are you going to release all 3 parts (I read comment from SC team member who claimed that it would be released by the end of the year, but it was 3 months ago)? Btw. Great pick. V3 seems to be much different than V2

Yea :/. The conference and holidays slowed things down. I don't know when... but I'm really hoping to dive through all 3 as quickly as possible vs ep 1, a break, ep2, a break, ep 3, which I know is annoying for everyone.

If there are some specific things that you'd like to see in the more advanced tutorials, now is a great time to let me know!


1 Reply
kyotomano Avatar

Thanks for your great and detailed answer. No, no. I don't expect to see Mercure in any "heavy" way/use. But would be cool to see it in action with api platform - 2 maybe 3 episodes (just like in symfony ux tutorial). I just find Mercure an interesting part that wasn't covered in any tutorial before and Api platform seems just right place to do it. There is also lack of such content. You have symfony docs where they explain how to set it up (a little too much in my opinion, should be divided into parts like: docker, binary and then setup with example - quick setup and detailed setup like .yaml) and use, but there is a lack of real example usage. On Api Platform website is example of chat, but lack of repo on GitHub to check code to see how it works. There is only one YT tutorial that is outdated about Mercure (and based on that, many people in comments ask and complain about not being able to set it up and learn - cause there is indeed no learning resource except docs => check Laravel and pusher, there is a lot of examples and even whole tutorials about that topic on YT or Laracasts). That's why I asked about that.

Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "api-platform/core": "^3.0", // v3.0.8
        "doctrine/annotations": "^1.0", // 1.14.2
        "doctrine/doctrine-bundle": "^2.8", // 2.8.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.14", // 2.14.0
        "nelmio/cors-bundle": "^2.2", // 2.2.0
        "nesbot/carbon": "^2.64", // 2.64.1
        "phpdocumentor/reflection-docblock": "^5.3", // 5.3.0
        "phpstan/phpdoc-parser": "^1.15", // 1.15.3
        "symfony/asset": "6.2.*", // v6.2.0
        "symfony/console": "6.2.*", // v6.2.3
        "symfony/dotenv": "6.2.*", // v6.2.0
        "symfony/expression-language": "6.2.*", // v6.2.2
        "symfony/flex": "^2", // v2.2.4
        "symfony/framework-bundle": "6.2.*", // v6.2.3
        "symfony/property-access": "6.2.*", // v6.2.3
        "symfony/property-info": "6.2.*", // v6.2.3
        "symfony/runtime": "6.2.*", // v6.2.0
        "symfony/security-bundle": "6.2.*", // v6.2.3
        "symfony/serializer": "6.2.*", // v6.2.3
        "symfony/twig-bundle": "6.2.*", // v6.2.3
        "symfony/ux-react": "^2.6", // v2.6.1
        "symfony/validator": "6.2.*", // v6.2.3
        "symfony/webpack-encore-bundle": "^1.16", // v1.16.0
        "symfony/yaml": "6.2.*" // v6.2.2
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "6.2.*", // v6.2.1
        "symfony/maker-bundle": "^1.48", // v1.48.0
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/stopwatch": "6.2.*", // v6.2.0
        "symfony/web-profiler-bundle": "6.2.*", // v6.2.4
        "zenstruck/foundry": "^1.26" // v1.26.0