Chapters
27 Chapters
|
2:54:11
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3
Subscribe to download the code!Compatible PHP versions: ^7.1.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Este tutorial funciona muy bien para Symfony 5 y la Plataforma API 2.5/2.6.
What PHP libraries does this tutorial use?
// 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.21.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
}
}
27 Comments
Hello,
If you are using Symfony 5 with PHP 8, you can use attributes :
`
#[ApiResource(
)]
`
Sweet! Thanks for sharing it
Hi everybody,
I cant understand a small things
When i add a path in the itemOperations :
for example :
And i go to the url : /api/cheese/1.json
i don't have the json format on screen, its the API Platform html screen.
But if i don't define a custom path i have the json format on screen.
I hope i explain this problem correctly.
Does anyone have an explanation to this ?
Thanks :)
Hi @David-G!
Yes, I know this issue! To fix it, change the path to
/cheese/{id}.{_format}.By default, THIS is how Api Platform creates routes - you can see it if you run
bin/console debug:router. So if you override the path, it becomes your responsibility to add this. It's a little "gotcha", but easy to fix once you understand the issue :).Cheers!
thank you !
In my ApiPlatform it shows 6 endpoint instead of 5 in the video. The new's one is PATCH. When I document this (if I understand correctly), PATCH is for modifying one property while PUT is for the entire Entity. But the exemple for Put in next video doesn't show this: It modify one property and stills work. So my question is: I will use PUT or PATCH for the update entity?
Hey Dang !
Yes, there is a new PATCH, I think it's new in Api Platform 2.5. The explanation of what's going on can be found here: https://github.com/api-platform/core/issues/4344#issuecomment-873418011
I have not worked with PATCH yet, but here is my understanding:
A) Currently PUT works "incorrectly" per the official spec. It, as you correctly said, allows you to modify one property at a time... even though it should require you to pass all the properties (i.e. a "replace"). Now that PATCH is supported, it appears that, in future versions of API Platform, PUT will change to be a "true" PUT.
B) So, to answer your question: you should probably start using PATCH for these "partial" updates right now (I'll add a note about this). When you do this, you may need to set the
Content-Typeheader on your request toapplication/merge-patch+json, but I'm not sure if that's a requirement - I need to play around with that to be sure :).Cheers and thanks for the poke to add a note to the video about this for other users!
I am trying to customise the request body for a PUT operation, how do I change the request body description in my code?
Current description is: "The updated cheeses resource"
Hey Sam Z.
Do you mean how to change the description of a field only for the PUT operation? Perhaps there's a way to do it by configuring the Swagger context https://api-platform.com/do...
Cheers!
defautl utf8 has been deprecated, if you use sf >= 4, setting the option is required:
{"path"="/i💚cheeses/{id}", "options"={"utf8":true}}Hey Steven J.!
Ah, good tip! I think you can also turn on utf8 globally in the config - https://github.com/symfony/... - it's a default option you get in your routing file if you started a new project today :).
Cheers!
How do you get a resource without using a primary key?
ex) /api/units/{otherId}
Hey Yoshiki T.
That's a good question and there are a few options:
A) Add a filter to your
/api/unitsendpoint that will match by the field you wantB) Change the resource identifier to the field you want
C) Create a custom
IriConverterthe easiest way is to use the decorate patternCheers!
Hi, how can I add a route to a Controller instead of an Entity?
Hey Jelle S.
You can still add routes to Controllers as normal but it's not recommended. You can read more info about it in the docs: https://api-platform.com/do...
Cheers!
Hi,
I'm used to working with Symfony to build traditional websites. I have started to learn API platform but I have many questions to ask because I am very confused.
Let's take an example of a traditional website to post adverts, this is how I organize it:
- An administrator can post and manage all adverts (add, edit, delete, list) via admin space.
- A member can also add, edit, delete and list his adverts only through his private space.
- A visitor can view the list of adverts and view the details.
I'm used to make 3 controllers for the Advert entity:
AdvertController in App\Controller\Admin which contains the CRUD and routes for the admin part
AdvertController in App\Controller\Front\MemberSapce which contains the CRUD and the routes for the member space
AdvertController in App\Controller\Front\PublicSpace which contains the CRUD and the routes for the visitor part
and I give the names of the routes like this:
- admin_advert_index , admin_advert_new , admin_advert_edit ....
- member_space_advert_index , member_space_advert_new, member_space_advert_edit ....
- front_advert_index , front_advert_show ...
When I started to learn API platform, I understood that there are 4 or 5 main operations (item and collections), but I didn't understand how to create other specific operations for each part (admin, front , member space)...
How to well organize my project, how for example an admin can manage all the adverts via admin space (not easyAdmin), how a member can manage only his own adverts via his private space. How we can create these all spaces ... Should we also create 3 others controllers like I'm used to do to build traditional website? If yes, so can a controller contain the CRUD or we should create a single class (persister I think) for each function ?
Really I am very confused and things are not clear. Can you help me and explain us how to organize a project with API platform?
I will be very grateful.
Thank you.
Because I have never created an API Rest and because this is the first time I'd like to ask you as you are an experienced developer.
What I'd like to say is, imagine that we have an item opreration "get" to retrive the Advert data and we have 3 spaces in my application (administration, MemberSapce and public) and the frentend developer who will create these 3 interfaces.
So does the frentend developer will consume the same operation (get) above to dispaly the advert data in each space and the backend developer uses the "groups" to tell who can show this attribute and can't show it ? Or I should have 3 routes and 3 operations ?
I'd like to undrestand this point to continue learning API platfrom and also because I have never seen how a frentend developer consume an API.
Thank you
Hey hous04 !
Welcome to the very-different world of APIs :p. Let me do my best to explain how *I* would handle this situation.
In short, even if I will have 3 different interfaces for my "Advert" data, I would only have 1 "ApiResources". That's not an absolute rule, but let's "start" with this :). From a data perspective, let's think about the 3 "interfaces" an how each might be different:
A) The "admin" interface will probably contain a list of "all" Adverts - not just the adverts "owned" by a specific user.
B) Some interfaces may "allow" extra fields to be displayed or set - e.g. in the "admin" interface, you may render "extra" data that normal users can't see or have extra fields that a normal user can't input.
C) The "member" interface probably also renders some data that is not rendered on the "public" space.
I think that all of these interfaces can be built from the same "Api Resource" via groups or custom normalizers (depending on the situation). For example, if you are logged in as an admin, then the Advert "collection" operation would return *all* Adverts. So naturally, if you are looking at the "admin" interface (which you will only allow people to access if they are an admin), this page will list ALL Adverts. The API endpoint would maybe also return "extra" admin-only fields because the user is an admin, which the frontend would display.
The only weird part is that if the admin THEN goes to their "member" interface and the JavaScript makes a GET request for the collection endpoint, it would return ALL Adverts, not just their *own* adverts. That could be solved with an "exact" SearchFilter - https://symfonycasts.com/sc... - the frontend would add something like ?owner=/api/users/5 to the URL inside the "member" interface to filter to only "my" adverts. If a "smart" user tried to hack this and change it to "/api/users/6" (some other user), you will already have ACL logic inside your system to prevent this - and it will return an empty set.
Also, if an admin goes to their "member" interface, the API may return "extra" fields or allow extra fields to be "submitted" because they are an admin. That's fine: the interface simply won't render that extra data or create "fields" to allow that data to be set. It's just "extra stuff" that the interface ignores.
For the "public" interface, you would probably want to display all... maybe "published" adverts or something. Again, I would use a filter and make the interface add a "?published=1" query parameter when you fetch the collection of them. If a "smart" user removed that flag to try to "hack" the system, you would (once again) already have logic in place to limit them to only view the adverts that their user level allows (an admin would see all adverts and a normal user might see all public adverts + private adverts that they own).
Does that make sense? There are 2 critical pieces to this:
1) Make sure you have a security layer that (on matter what) only allows people to list/show/edit the exact adverts that they should have access to. And also, a security layer that (no matter what) only allows people to "write" the exact fields on Advert that they should be allowed to write (and the same for "read").
2) Then, use filters to "allow" front-end developers to "limit" the list (and maybe even "fields" if you care enough - via sparse fieldsets) in whatever way they need to in order to create the interfaces they want.
Let me know if it helps! You *may* still need custom "actions" or other custom things - like maybe if you need a special endpoint to "publish" an Advert - but that's a separate conversation from "how do I use 21 ApiResource to power 3 interfaces. And if your interfaces are VERY different, you could also *decide* to have one ApiResource per interface if you want. This would not mean 3 Doctrine entities: it would mean creating 3 "model classes" (one for each interface) and then using a custom data persister, etc to populate that manually from your Advert data. This is a bit more advanced and may not be needed.
Cheers!
Hi
Yes , it's "very-different world" :p , it's clear now and I will try to apply your advices.
Thank you
Hi, how did you made that heart appear with /i?> cant get it
Hey Tadis
That "heart" icon is an utf8-mb4 emoji. If you are using PHPStorm you can install this plugin https://plugins.jetbrains.c... and insert emojis into your code very easily.
Cheers!
Thanks so much Diego :)
One thing is not clear for me after this video. If I need to create custom action e.g. I need to unpublish post and do many many different operations during this operation (delete comments, send email for subscribers, reindex ES, invalidate cache etc.).
So it is not patch for "/post/145" with "is_published": 0 it is big action with independent logic.
I would like to have /post/145/unpublish or something like this which will be resolved to PostController::unpublish where I will do all needed operations and output the same data as standard PATCH method.
I saw on the page https://api-platform.com/do... how to make custom operation for controller, but how to force api-platform to do docs, output etc. same as for PATCH?
Hey Andrey S.!
Such a simple question, and yet this is such a loaded topic :). It's something we'll cover in a future tutorial. BUT, I'll give you some hints (but also, there is not one perfect answer). Creating a URL like /post/145/unpublish is not RESTful. So, you're "breaking" the rules... which you should avoid if you can... but also... at some point - damn the rules and get your job done. So yes, this is one possible approach - but I would make it POST (instead of PATCH) - just because POST tends to be the best option (meaning, the one that follows the rules the "most") for these non-RESTful endpoints, imo.
Anyways, I have not played much with custom operations (as it's something we're covering later), but if you follow the docs about custom operations - https://api-platform.com/do... - does this not generate any API docs? Let me know :).
Cheers!
I could not find shortName in official documentation. From where it comes?
Hey Adrian,
Yeah, it sounds like missing feature in docs, probably they didn't want to complicate example with annotations. I found this shortName for Yaml/XML mapping only on this page: https://api-platform.com/do... - though their search does not find it either, I searched with Google instead.
Cheers!
"Houston: no signs of life"
Start the conversation!