Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

API Platform: Serious RESTful APIs

2:54:11

What you'll be learning

This tutorial works great for Symfony 5 and API Platform 2.5/2.6.
// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "api-platform/core": "^2.1", // v2.4.3
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/annotations": "^1.0", // 1.10.2
        "doctrine/doctrine-bundle": "^1.6", // 1.11.2
        "doctrine/doctrine-migrations-bundle": "^2.0", // v2.0.0
        "doctrine/orm": "^2.4.5", // v2.7.2
        "nelmio/cors-bundle": "^1.5", // 1.5.5
        "nesbot/carbon": "^2.17", // 2.19.2
        "phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
        "symfony/asset": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/console": "4.2.*", // v4.2.12
        "symfony/dotenv": "4.2.*", // v4.2.12
        "symfony/expression-language": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/flex": "^1.1", // v1.17.6
        "symfony/framework-bundle": "4.2.*", // v4.2.12
        "symfony/security-bundle": "4.2.*|4.3.*", // v4.3.3
        "symfony/twig-bundle": "4.2.*|4.3.*", // v4.2.12
        "symfony/validator": "4.2.*|4.3.*", // v4.3.11
        "symfony/yaml": "4.2.*" // v4.2.12
    },
    "require-dev": {
        "symfony/maker-bundle": "^1.11", // v1.11.6
        "symfony/stopwatch": "4.2.*|4.3.*", // v4.2.9
        "symfony/web-profiler-bundle": "4.2.*|4.3.*" // v4.2.9
    }
}
// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "api-platform/core": "^2.1", // v2.4.3
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/annotations": "^1.0", // 1.10.2
        "doctrine/doctrine-bundle": "^1.6", // 1.11.2
        "doctrine/doctrine-migrations-bundle": "^2.0", // v2.0.0
        "doctrine/orm": "^2.4.5", // v2.7.2
        "nelmio/cors-bundle": "^1.5", // 1.5.5
        "nesbot/carbon": "^2.17", // 2.19.2
        "phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
        "symfony/asset": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/console": "4.2.*", // v4.2.12
        "symfony/dotenv": "4.2.*", // v4.2.12
        "symfony/expression-language": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/flex": "^1.1", // v1.17.6
        "symfony/framework-bundle": "4.2.*", // v4.2.12
        "symfony/security-bundle": "4.2.*|4.3.*", // v4.3.3
        "symfony/twig-bundle": "4.2.*|4.3.*", // v4.2.12
        "symfony/validator": "4.2.*|4.3.*", // v4.3.11
        "symfony/yaml": "4.2.*" // v4.2.12
    },
    "require-dev": {
        "symfony/maker-bundle": "^1.11", // v1.11.6
        "symfony/stopwatch": "4.2.*|4.3.*", // v4.2.9
        "symfony/web-profiler-bundle": "4.2.*|4.3.*" // v4.2.9
    }
}

API Platform is crushing the scene these days. And it's easy to see why! Built on top of Symfony, API Platform enables you to build a rich, JSON-LD-powered, hypermedia API... pretty much instantly! In this tutorial, we'll build a real app and leverage these tools:

  • Setting up API Platform in a Symfony app
  • Swagger, OpenAPI & JSON-LD+Hydra: what they are and why they're awesome
  • Creating ApiResources
  • Customizing the operations
  • IRIs & how to control them
  • Resource relations
  • Embedded resources & Subresources
  • Filters
  • Pagination
  • Validation
  • The serializer & controlling input/output fields

Your Guides

Niels van der Molen Ryan Weaver

Buy Access

Join the Conversation?

78
Login or Register to join the conversation
Stefan T. Avatar
Stefan T. Avatar Stefan T. | posted 3 years ago

Finally

6 Reply
dugi Avatar

This is what I was looking for !!

3 Reply
vLoght Avatar

what about "API Platform: OAuth2 Server" tutorial ?

2 Reply

Hey vLoght!

Interesting idea... it's not currently on my list to cover for the next "security" tutorial... because they're kinda two separate things. But, I've upvoted this in our internal idea list - it's something that we *may* cover, but I don't have any timing yet.

Cheers!

3 Reply
Default user avatar

I'm waiting for api-platform and oauth2. :)

Reply
Ad F. Avatar

Thank you !

1 Reply
Ad F. Avatar

any news ?

1 Reply

Wednesday :)

2 Reply

Bah, ok *tomorrow*, I promise - we hit a last-second snag. Sorry about that!

Reply
Default user avatar
Default user avatar Romeo Tong | posted 3 years ago

It's good.
I'm going to add GraphQL into Api-Platform and also with Symfony Flex.
Did you include CRUD by GraphQL in this course? please.

1 Reply

Hey Romeo,

Thank you for your feedback! We will cover CRUD in this course, and will slightly mention GraphQL, but, unfortunately, GraphQL won't be a part of basics. We're going to cover GraphQL in a separate course - this topic deserves a separate tutorial.

Cheers!

2 Reply
Default user avatar

Nice!

1 Reply
Default user avatar
Default user avatar Imad Zairig | posted 3 years ago

Cool,
does this course cover API security with API-Platform ? :)

1 Reply

Hey Imad,

Unfortunately no, not in this episode at least. Security is a big separate topic, we're definitely going to cover it, but in next episodes. In this one we're going to cover basics only. Thank you for understanding!

Cheers!

2 Reply
infete Avatar

It would be nice to have it

1 Reply

Hey Manoj,

Thank you for your interest in this topic! See my answer for more context: https://symfonycasts.com/sc...

Cheers!

Reply
Richad-H Avatar
Richad-H Avatar Richad-H | posted 10 days ago

hey, I want this course to be updated becauce I see that the code you are using is becoming obsolete

Reply

Hey Richad-H!

It's planned! Work hasn't started yet, but this is a high priority for me - time to update this for API Platform 3!

Cheers!

Reply
Default user avatar
Default user avatar GianlucaF | posted 3 months ago

I'm using shortName, but apparently the ApiPlatform add an "s" at the end. The problem is that my entity is called "Area" and plural is "Area" .
Is there a way to avoid ApiPlatform to add the "s" at the end of entrypoint?


/api/area/1
instead of
/api/areas/1

Reply

Hi!

This might be a stretch, but I'm trying to deploy my symfony app with IIS.

Does anyone know how I can get this to work?

Reply

Hey Shane,

Unfortunately, we don't have any screencasts about deploying with IIS unfortunately, but we do have a tutorial about deploying in general, so probably you could take a look at it and find if useful for your case: https://symfonycasts.com/sc... - the Ansistrano is a special tool that allow you to deploy any project (not only written in PHP) to any server. It's based on Ansible language, but it's pretty simple and intuitive one, so you don't have to know Ansible to start with Ansistrano course. But in case you would like to know more about it and understand it even better - we have a separate course about it too: https://symfonycasts.com/sc... - but as I said, it's just in case you want to learn it in deep, it's not required for starting Ansistrano course :)

I hope this helps, sorry we can't help more!

Cheers!

Reply

Hello,
if api have possibility of calculated field - as example average(wind, rain or others) by some date range ?

Thanks in advance

Reply

Hey Mepcuk!

Hmm, I'm not totally sure I understand your question. You CAN have calculated fields (but I think you probably already know this)... but I'm not sure what you mean by "date range". What would the API call look like (e.g. GET /api/cities?start_date=..) and was is the expected JSON result?

Cheers!

Reply

I have weather endpoint where stored all weather data. Now i need to get average, GET /average_weather/city?start_date=?&end_date= my idea is inject via construct into plain entity average_weather weather repository. Create method in repository getAverage with start and end date parameters? It is correct way?

Reply

Hmmm. The first question is: what does the response data look like for a normal call to the "weather" endpoint (like what fields are in the JSON)? And what will the fields look like in this new "average weather" endpoint? If they are significantly different, then I think you are possibly dealing with an entirely new "API Resource" - e.g. AverageWeather (which would be a non-entity resource) - you even structured your URL with this in mind - GET /average_weather/city.... Also, would the "average weather" endpoint always return just ONE result?

I'm sorry I'm not giving many answers yet - there are just a lot of variables. Your idea won't quite work, but we could make it work. Instead of trying to inject the repository into the entity, I would create a custom data provider that extends/uses the normal "entity provider". This custom data provider would allow the "entity provider" to do its normal work... but THEN you would calculate the "average" temperature and set it into a non-persisted field - e.g. setAverageTemperature(). This property would be exposed to the API. To read the query parameters, you could keep it simple and inject the RequestStack into your custom provider and read them manually.

Buuuuut, whether this is the right way depends on the above questions :).

Cheers!

Reply

I was looked your Api 3 part and all questions are now clear. No more question. You just said please can you look my Api part 3 ))) thank you for awesome video tutorials

1 Reply

I think it is another endpoint GET /average_weather - only average data in JSON (like wind, rain - two results between date range) about all cities (it is partial data GET / weather_station/city - include all data about station - city) Thank you for idea, i looking into custom data provider. If on symfonycast exist similar video ? Huge thanks for help

Reply

Hey Mepcuk!

Excellent! Then sounds more to me like a totally separate ApiResource vs an extra "operation" on an existing ApiResource... but I'm still not entirely sure. Usually you will return the same fields in all situation for one ApiResource. The fact that you will be returning different data makes me think it is a new/separate ApiResource. Though, again, I could be wrong... if the data between the normal /weather_station/city and /average_weather are quite similar.

Anyways, related screencasts:

A) Custom data provider: https://symfonycasts.com/sc... and the next few chapters
B) Totally custom ApiResource class (e.g. AverageWeather): https://symfonycasts.com/sc...

Cheers!

Reply
Gaetano S. Avatar
Gaetano S. Avatar Gaetano S. | posted 1 year ago

Hello everybody,
I need some advises about a work project. This is the idea: a front-end with flutter and a back-end rest api + admin back-office. An important functionality of this project is the multi-language (7 languages), so the admin back-office must handle a lot of contents and storing in the db (MariaDB). For the back-office Strapi should do the job about multi-language, so I would like to us it like a CMS (it is connected to MariaDB) and in the same time exposing the routes. Then, I would like to use ApiPlatform for security and the logic. Essentially ApiPlatform exposes the routes for the front-end and get the info by the routes exposed from Strapi. This way the back-office and the DB are not exposed on internet. Maybe I'm not doing the good choice and I will appreciate any advises. Thanks for your time.

Reply

Hi Gaetano S.!

Sorry for my very slow reply! I don't know Flutter or Strapi, so I probably can't give a lot of great opinions on this. However, as an outside, I'll admit that the setup looks complex - with a mixture of a headless Node CMS, Api Platform, etc - it's a lot. It totally might be necessary - but if you can start simpler, that's always a good choice.

Good luck!

Reply
Gaetano S. Avatar

Finally I think I will use only Strapi because I need something built-in for content internationalisation. And then I will use an API gateway to protect it.
Anyway always thanks for your time.

Cheers

Reply

Thank you ! just a quick question, for a given project, according to what criteria we decide to either implement a purely Symfony * MVC architecture * to develop both the front side (ex with Twig) and the back or to implement a micro-services architecture under an API developed with Symfony (ex with APIplatfom) and consumed by a framework JS for the front part ?

Cheers!

Reply

Hey Ahmedbhs,

IMO, it should come from your business criteria :) Micro-service architecture suppose you have at least a few standalone applications, and if some application is unavailable, like broken or attacked - the main application still works well but with limited functionality. But once again, it should come from your business needs, from your project, probably you even don't need that complexity. Basically, if you need a complex single-page application - you probably should look into the direction of API, as you would want to generate only data on the server side and render the view on the client side base on the data your API return. But single-page app is not required for you - take a look at MVC instead to prepare the whole page on your server side and return the already generated HTML page to your end users - it should be more straightforward and simple. But still, on your MVC project you can still leverage some AJAX requests to make some parts of your application work without page reloading.

I hope this helps!

Cheers!

Reply

I am evaluating the API Platfrom to migrate a few of my applications. I narrowed down to the API platform after evaluating offerings from other PHP framework vendors and even workflow applications. My initial feedback is as follows

1. Its easy to setup (having come from PHP/Drupal background)
2. Creating entities is extremely easy (the decorator patternusage is awesome) but then the documentation (https://api-platform.com/do... is not in sync with the application. For example the documentation declares all variables as "public" though Doctrine specifically mentions that variables should be "protected" or "private". Creating relationships between entities is a bigger challenge. After reading the Doctrine docs, Symfony/Doctrine docs and a whole bunch of other literature on the web I wonder if its really necessary to create entity relationships in an API based scenario the architect side of me says that it should i.e. all logic should be in the middle tier while the programmer in me says its not worth the effort as what is POSTED to the middle tier can be controlled at the UI!
3. Disabling HTTP verbs and hence operations is awesome
4. Setting pagination parameters at the entity level is a blessing allows me to set the number of records per page for each collection.
5. The documentation (https://api-platform.com/do... nor symfony casts covers all aspects of creating data fixtures for testing. Following the docs at https://github.com/hauteloo..., https://github.com/nelmio/a..., https://github.com/theofidr..., https://github.com/trappar/... and https://github.com/fzaninot... got me even more confused.

It would be nice if the documentation is updated to reflect some challenging applications. Books and Reviews are very simple use cases. In enterprise applications there are restrictions on the values that fields can take for example a field for short codes that designates a document template in my application can take eleven different values so I tried this in my fixture fstype_ShortCode: <randomelement($shortsode =="" array="" ('bs','is','dr','mr','cs','ar','fp','pl','me','cf','no'))=""> The description should match the code. I havent found a way to create a fixture for it from the documentation. I also get errors while loading it.

I am yet to explore the rich set of filters that the API Platform explores, and a deployement before I roll it out to the developers. Once done I am looking at setting up a CI/CD using Jenkins or Docker. Hope the documentation covers these aspects. I am willing to engage on an ongoing basis to do my bit for the documentation and to help out in the forums and on StackOverflow. Hope my feedback helps.

Reply

Hi sridharpandu!

It sounds like you've done some excellent research! I am not personally responsible for API Platform and its docs, but I know the team that is, and I'm sure they would love any updates or improvements that you could make to the documentation :). I can give some of my thoughts on some of your points:

> nor symfony casts covers all aspects of creating data fixtures for testing

I agree! We do cover this in a much more interesting way in our latest tutorial on API Platform - you can see some of the setup here using a cool library called Foundry - https://symfonycasts.com/sc.... I dislike many of the tools like Alice that are mentioned by API Platform. Foundry makes added data (in fixtures and a test) an absolute joy and comes with nice features like automatically resetting the database between tests. You will be able to do your "short code" thing in the fixtures very easy, as it's just PHP code :).

Cheers!

1 Reply

Thank you for the link to Foundy. Will check it out.

Reply
Joel L. Avatar
Joel L. Avatar Joel L. | posted 1 year ago

Hi,
when did you plan the GraphQL course ? After the 2.6 release i guess ?

Reply

Hey Joel L.!

To be honest, I'm not sure. It depends on the demand for that... and I haven't had a *ton* of people asking about GraphQL yet... though that might change.

Sorry I can't give you a better answer!

Cheers!

Reply

Hello Everybody,
I am new with api platform and i find it's a great framework to make Rest APIs. I have some questions :
1 - Is api Platform suitable for making microservices ? My matter is i have an openapi specs and i want to generate php classes to handle the request. The request will probably make crud operations of many entities and not only one so i can't just diretly use doctrine models. how do i i handle this bestens ?
2 - Is there a tool you suggest to auto generate symfony / doctrine classes from openapi specs to use it with api platform ?

Thanks in advance.

Reply

Hi soufianejhioui!

Welcome to the nice world of API Platform :).

> 1 - Is api Platform suitable for making microservices ?

Sure! It makes creating APIs quick and easy - I don't see any problem here.

> My matter is i have an openapi specs and i want to generate php classes to handle the request. The request will probably make crud operations of many entities and not only one so i can't just diretly use doctrine models. how do i i handle this bestens

It sounds to me like you would want to create custom "model classes" for your API resources. This is not something we cover in our tutorial, but it's a fairly common use-case. Basically, instead of adding @ApiResource to an entity, you would create a class in the src/Entity/ directory (you could put it somewhere else, you would just need to update some API Platform config to look in the new directory), NOT make this class an entity, and then add @ApiResource to THIS class. You would then design this class to match your OpenAPI spec exactly: this gives you the power to design your API like you need, even if it looks quite different than your database entities. Finally, in order for API Platform to know how to fetch and persist data for your non-entity class, you will need to create a custom "data persister" - example https://symfonycasts.com/sc... - and a custom "data provider" - https://api-platform.com/do...

Let me know if that helps :).

> 2 - Is there a tool you suggest to auto generate symfony / doctrine classes from openapi specs to use it with api platform ?

I do not think that there is. In your case, since you said that your OpenAPI spec looks quite different than your database entities would probably look, you wouldn't want to generate "entities" from your OpenAPI spec anyways: you really want to create non-entity classes that match exactly. And I don't think there is a way to generate in this direction. The reason is that API Platform is kind of meant to be used in the *other* direction: you create the ApiResource classes and customize them, and then ApiPlatform *generates* the OpenAPI document based on your classes. In your case, I think you would need to create the classes by hand, then customize them until the OpenAPI document generated by API Platform matches the one you have currently.

Cheers!

Reply

Hello,
First of all thanks fir this great tutorial ; it's really interesting and forgive my poor English...
So, i try to start with Api Platform and my first question is How to generate Api Models from an existing database. It mut be a lot of Symfony tools to do this. Is there any one that you suggest ? a Tutorial for this maybe ?
thanks in advance.

Reply

Hey soufianejhioui !

> First of all thanks fir this great tutorial

Cheers! And welcome :).

> How to generate Api Models from an existing database. It mut be a lot of Symfony tools to do this.

What you *really* want to do is generating a set of Doctrine entity classes from your existing database. Once you have done this, you only need to add the @ApiResource annotation to convert the entity class into an API resource.

The tool to do this is here: https://symfony.com/doc/cur... - it's not perfect (well, it will do a perfect job if your database is "perfect" and "normalized", but not a perfect job if your database has some "weirdness"), but it should give you a set of "nearly correct" entity classes. You can then "tweak" the @ORM\ annotations to (hopefully) make it perfect. The goal would be that you are able to run php bin/console doctrine:schema:update --dump-sql and this returns NO sql. This would mean that your Doctrine entities "match" your database structure perfectly. Then add @ApiResource to each entity and you're good!

How well this will work (or not work) depends on how normalized your existing database is. Doctrine likes databases to be "neat" and "normalized", You can make Doctrine work with a very non-normalized database, but it requires more setup work.

Cheers!

Reply

Hi weaverryan
Thanks for the reply. I will give the tool you suggest a try and see the result. As you said it's just fine if i get a set of "nearly correct" entity classes that will be a nice start.
Cheers !

Reply
Roland W. Avatar
Roland W. Avatar Roland W. | posted 2 years ago

This course "only" covers CRUD operations, right? Is it possible/wise to use API Platform if you plan to design an API that supports non-CRUD operations? You can find some examples in this question on Stackoverflow: https://stackoverflow.com/q...


But what to do with the rest of the use cases?

– HoldDealUseCase(id, reason);
– UnholdDealUseCase(id);
– CompleteDealUseCase(id, and many another params);
– CancelDealUseCase(id, amercement, reason);
– ChangePriceUseCase(id, newPrice, reason);
– ChangeCompletionDateUseCase(id, newDate, amercement, whyChanged);
– etc. (total 20 use cases)...
Reply

Hey Roland W.!

> This course "only" covers CRUD operations, right

Haha, yes. That's not exactly on purpose - it's a product of REST - REST fits most "cleanly" for CRUD operations and API Platform is all about REST. On a philosophical level, we talk about these in an older tutorial - https://symfonycasts.com/sc... and the chapter after that :).

So, the first thing to figure out is how you want to implement this simply from an HTTP perspective (not thinking about API Platform). Sometimes these things just *aren't* very RESTful. That's not idea... but you still gotta get your work done at the end of the day. For example, I might decide to:

– HoldDealUseCase(id, reason); - POST /api/deals/{id}/status with { hold: true }
– UnholdDealUseCase(id); POST /api/deals/{id}/status with { hold: false }
– CompleteDealUseCase(id, and many another params); POST /api/deals/{id}/complete with { params } OR maybe you consider this the creation of a new "completed deal" resource, in which case it would be POST /api/completed-deal where the "deal" is in the JSON
...
– ChangePriceUseCase(id, newPrice, reason); PUT /api/deals/{id} and you send "price" and "reason" as fields. This may or may not work if you need to force the new price change to always have a reason. You might also consider that this is the creation of a new "price change" reason - in which case, you might have POST /api/price-change or by leveraging a sub-resource, you could tweak the URK to POST /api/deals/{id}/price-change
...

For several of these, I listed multiple possible solutions. And each solution would be implemented differently. Some of the solutions DO fit just fine into CRUD. For the others, you have a few options. And this is all stuff that we're planning to cover in our next episode of this tutorial. Options include:

* A DTO API resource
* Symfony Messenger integration
* Last resort, a custom controller/action

You might also like this open documentation issue: https://github.com/api-plat...

Let me know if that helps!

Cheers!

Reply
Emmanuel B. Avatar
Emmanuel B. Avatar Emmanuel B. | posted 2 years ago

What api-platform version is this podcast about?

Reply

Hey Evelair,

I just double-checked it for you: downloaded the course code and checked the installed version of API Platform in composer.lock - "api-platform/core" package is locked on v2.4.3. The latest is 2.5.4, but I remember we added some notes in this course according to some changes that were done in 2.5 minor release.

I hope this helps!

Cheers!

Reply
Emmanuel B. Avatar
Emmanuel B. Avatar Emmanuel B. | victor | posted 2 years ago

Thank you very much for checked it!

Reply
Isaac E. Avatar
Isaac E. Avatar Isaac E. | posted 3 years ago

I'm hoping you'll add a lesson about transformers (dtos)

Reply

Hey Isaac E.!

We will in the next tutorial :). That will be a bit more about customizations, including custom operations and DTO's.

Cheers!

Reply
Cat in space

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