> APIs >

Course Overview

API Platform 3 Part 1: Mythically Good RESTful APIs

  • 3315 students
  • EN/ES Captions
  • EN/ES Script
  • Certificate of Completion

Your Guides

About this course

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
    }
}

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
    }
}

Need to build an API and love the process? You've come to the right place.

Built on top of Symfony, API Platform enables you to build a rich, JSON-LD-powered, hypermedia API... pretty much instantly (we'll even teach you what those buzzwords mean). In this tutorial, we'll build a real app including:

  • Setting up API Platform in a Symfony app
  • Buzzwords: Swagger, OpenAPI & JSON-LD+Hydra
  • "Exposing" a Class to your API via ApiResource
  • Customizing operations
  • All about serialization and controlling input/output fields
  • IRIs & how to control them
  • Related resources
  • Embedded resources & Subresources
  • Filters
  • Pagination
  • Validation
  • Formats & Content-Type Negotiation
  • Bonus: React Admin

Next courses in the APIs: API Platform 3 section of the APIs Track!

29 Comments

Sort By
Login or Register to join the conversation
Evgeny avatar Evgeny 8 months ago

Great lessons, thanks! Is there a video on how to use GraphQl based on Api-Platform?

1 | Reply |

Hey @Evgeny

We do not cover QraphQL in these videos but ApiPlatform docs are very good, you may want to give it a read https://api-platform.com/docs/core/graphql/

Cheers!

1 | Reply |

It's a pity, as always, not everything is clear from the documentation, for example, how can I return DTO instead an entity object. It would be great if you recorded additional videos on graphql.

| Reply |

Thanks for your feedback, I'll pass your message to the team. We love to know what our users want to learn. In the meantime, I can recommend you to watch these videos where we introduce a DTO into an ApiPlatform project, but it's written for version 2, however, the logic is still relevant but the code will change for version 3
https://symfonycasts.com/screencast/api-platform-extending/output-class

Oh, and here are the docs about DTOs https://api-platform.com/docs/core/dto/

Cheers!

| Reply |

Oh, and also, I'm literally coding up episode 3 right now - https://symfonycasts.com/screencast/api-platform3-extending - where we go extensively into DTO's :)

1 | Reply |

Thanks for the answer! Will annotations with api-platform settings work for a graphql?

| Reply |

I'm not sure about that. As far as I know, ApiPlatform 3 moved from annotations to PHP attributes, which are faster and more reliable.

| Reply |
Pawel_Liszka avatar Pawel_Liszka 1 year ago

Thank you very much, Ryan - the guide fell from heaven! A few days ago I was just watching the previous version of the guide to the API Platform but with symfony 6.2 it worked quite averagely! I'm waiting for the next episodes! :)

1 | Reply |

Haha, quite "averagely", I would agree! Looking at all the old syntax - the annotations, etc - no fun. We're going to get these out as quickly as we can - I've nearly got all of the audio recorded (and all the video is already done).

Cheers!

4 | Reply |
Yangzhi avatar Yangzhi 4 months ago edited
        new Post(
            '/share_files/upload.{_format}',
            inputFormats: array('multipart' => 'multipart/form-data'),
            deserialize: false,
            processor: UploadFileProcessor::class
        ),

hi,use api upload file,can not use processor,will get

"Could not resolve argument $data of \"api_platform.action.placeholder::__invoke()\", maybe you forgot to register the controller as a service or missed tagging it with the \"controller.service_arguments\"?"

only working by custom controller。
right?
thanks

| Reply |

Hey @Yangzhi!

Sorry for my very slow reply! Ok, on a very low level, the error means that you're missing a "data" request attribute. This is normally set via one of the listeners. I believe, in the case of a POST, that it's set right here - https://github.com/api-platform/core/blob/main/src/Symfony/EventListener/DeserializeListener.php#L102-L106

Assuming I'm correct, the question is: why does that listener exit before setting the request attribute? Based on tour deserialize: false - I'm guessing it's this line - https://github.com/api-platform/core/blob/main/src/Symfony/EventListener/DeserializeListener.php#L84 - but I know why you have deserialize: false. On the docs - https://api-platform.com/docs/core/file-upload/ - they also show setting a custom controller for this (which would not require that data attribute). You might just be missing that part?

Cheers!

| Reply |
Yangzhi avatar Yangzhi 8 months ago

hi,the post operation need return one object,but sometimes i want return collection by post, and i created customer controller and uritemplate,can you teach how to return collection please.thanks

| Reply |

Hi @Yangzhi!

Hmm. I'm honestly not sure how to do this - and I would avoid it if possible. It's very not RESTful (the POST endpoint is supposed to be a singular endpoint, but in creating a single item and returning a single item), which is fine (you don't always need to follow the result), but as API Platform tries to be RESTful, doing something like this is quite custom. There MAY be some trick to do it, but I'm not sure. Again, I'd try to avoid this... but you could perhaps create a totally custom operation via a controller to try to do this.

Good luck and sorry I can't be more helpful!

| Reply |
Yangzhi avatar Yangzhi 11 months ago

how to return exception message on production environment?

| Reply |

Hey @Yangzhi

You need to catch the exception, probably in your controller, and just return a response as always, you can set the response with the exception error message, and also set the HTTP status code accordingly

Cheers!

| Reply |
May-S avatar May-S 1 year ago

Hello!
Thank you very for the tutos.
At the moment I'm trying to set an offset (using offset instead of page), but I cannot override the actual pagination (I cannot setFirstResults of the queries), any ideas plz ?

| Reply |

Hey @May-S

Thanks for your kind words. About your question, I'm not sure what you mean by "using an offset" but have you read the last topics of the documentation? https://api-platform.com/docs/core/pagination/#controlling-the-behavior-of-the-doctrine-orm-paginator
I believe you'll need to extend or create a custom paginator

Cheers!

| Reply |

Hey @MolloKhan thanks for your reply.
I mean by my question, that I can pass a param named 'offset' or 'started_from' in the query and then this offset which gonna be set in the first result of the query. It's the same aspect searched here https://github.com/api-platform/core/issues/4672.
I've tried to create an extension for the paginator but the class https://github.com/api-platform/core/blob/main/src/Doctrine/Orm/Extension/PaginationExtension.php is final. Have any ideas plz ?

| Reply |

Ohh, it seems like they never implemented that feature. You'll have to decorate the PaginationExtension class then, or create a custom paginator. Here's an example about how to decorate an ApiPlatform service https://api-platform.com/docs/core/state-processors/#creating-a-custom-state-processor

I hope it helps. Cheers!

| Reply |

Hello!
Thanks, but It does not solve the problem.
However I've set a solution, for anybody who need it https://github.com/api-platform/core/issues/4672#issuecomment-1557480806.

1 | Reply |
Rokas-P avatar Rokas-P 1 year ago

Thanks. Though why no information about new state providers?

At the moment I'm struggling to use Custom DataProvider with DTO to GetCollection data.
I manage to get the data, but the pagination info is gone :(

| Reply |

Hey @Rokas-P!

Unfortunately, custom data providers will be covered, but not until episode 3. If you're trying to customize how a collection of entities is returned, then you should use a query extension instead. If this is a more custom source, I haven't done this yet, but you can look at how the ORM pagination works. The process is:

A) CollectionProvider is the provider used for the ORM: https://github.com/api-platform/core/blob/main/src/Doctrine/Orm/State/CollectionProvider.php

B) At first, it looks like there is nothing related to pagination, and this returns the final result on the bottom. BUT, just above the bottom, it checks to see if any extensions implement QueryResultCollectionExtensionInterface. And they do, it calls them and returns THAT result instead. This is a sneaky way of calling PaginationExtension: https://github.com/api-platform/core/blob/main/src/Doctrine/Orm/Extension/PaginationExtension.php

C) PaginationExtension::getResult() returns a Paginator object. THAT is the key.

So the long story is that, if you want your custom data provider to allow pagination, instead of returning the array of results, you should return a Paginator. Well, not THAT Paginator, as that's from the ORM. I think you'll need to create a custom class that implements PaginatorInterface (or more likely extends AbstractPaginator).

Let me know if this helps :).

Cheers!

| Reply |
Ousmane-N avatar Ousmane-N 1 year ago

Thanks Ryan, nice start !
Any chance to see a tutorial about client generator for nuxt 3 ?

| Reply |

Hey,

Thanks for feedback and course idea!

Cheers!

| Reply |
Martin-M avatar Martin-M 1 year ago

Very nice! Thanks for the good work! Is there any chance you'll be doing an upgrade guide from 2.6/2.7 to >3 like you did for Symfony 5.* to 6? That one helped me a loooot :)

| Reply |

Hey Martin!

Hmm, maybe! I have one other friend that is doing the upgrade on a pretty big project and has been hitting some issues. Are there any specific things with upgrading that you're interested in? Or just a general request because you'll need to upgrade an app at some point?

Cheers!

| Reply |

Hy Ryan,

sorry for the late answer.

I'm working on a project with multiple Microservices which are based on Symfony 5.4 and Api-platform 2.7. These will have to be upgraded to Symfony6 and Apip3 sooner or later. In my opinion better sooner than later. The heavy lifting was done in the upgrade from 2.6. to 2.7 with the new syntax, but there are some deprecations I just don't seem to get rid off.
And that's the point where your upgrading symfony course really helped me and I would have the hopes, that upgrading apip would do the same :D

for example:

Since api-platform/core 2.7: The $exceptionOnNoToken parameter in "ApiPlatform\Symfony\Security\ResourceAccessChecker::__construct()" is deprecated and will always be false in 3.0, you should stop using it.
| Reply |
Martin-M avatar Martin-M Martin-M 1 year ago edited

Ignore that deprecation in my last comment. I upgraded to Symfony 6.2 and apip 3.1 just to see if it works and this and another deprecation just went away. A bit jarring for me, because I don't have that much Symfony experience, but sometimes you just have to try.

| Reply |

Nice work Martin! That deprecation indeed looks odd. The deprecations system in Symfony is GREAT, but sometimes they're a bit internal and it's not obvious what's needed :)

| Reply |

Delete comment?

Share this comment

astronaut with balloons in space

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