gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Welcome back you wonderful JSON-returning people, to API Platform episode 2. In part 1, we got busy! We created a pretty killer API to store dragon treasures, though... we completely forgot to add security! Any small, hairy-footed creature could sneak in a back door... and we'd have absolutely no idea! So this time, we're talking everything related to security. Like authentication: should I use a session with a login form... or do I need API tokens? And authorization, like denying access to entire endpoints. Then we'll get into trickier things like showing or hiding results based on the user and even showing or hiding certain fields based on the user. We'll also talk about totally custom fields, the PATCH HTTP method and setting up an API test system your friends will be jealous of.
Now, you know the drill: to really dig into this stuff, you should code along with me. Download the code course code from this page. After you unzip it, you'll find a start/
directory with the same code that you see here. Pop open this nifty README.md
file and go through all the setup instructions.
I'm all the way down here at starting the symfony
web server. So I'll spin over to a terminal that's already inside the project and run
symfony serve -d
to start a local web server in the background. Perfect! I'll hold Cmd
and click that URL to pop that open in my browser. Hello Treasure Connect! This is the app we created in episode 1... though we worked exclusively on the API. We created endpoints for treasures, users and the ability to relate them.
This homepage is brand new for episode 2. It's a small Vue app that I built. It has a login form... but it doesn't work yet: it will be up to us to bring it to life.
Now before we dive into security, one question I sometimes get is:
Hey Ryan, the interactive docs are super cool... but could I hide them on production?
If your API is private - it's just meant for your JavaScript - that might make sense because you don't want to advertise your endpoints to the world. However, I don't feel too compelled to hide the docs... because even if you do, the endpoints still exist. So you're going to need proper security anyways.
But yes, hiding them is possible, so let's see how. Even if you will show your docs, this is kind of an interesting process that shows how various parts of the system work together.
Find your terminal and run:
php ./bin/console config:dump api_platform
Remember: this command show all the possible configuration for API Platform. Let's see... search for "swagger". There we go. There's a section with things like enable_swagger
, enable_swagger_ui
, enable_re_doc
, enable_entrypoint
, and enable_docs
. What does all that mean?
First I want to show you what ReDoc is, because we didn't talk about that in the first tutorial. We're currently looking at the Swagger version of our documentation. But there's a competing format called ReDoc... and you can click on the "ReDoc" link at the bottom to see it! Yup! This is the same documentation info... but with a different layout! If you like this, it's there for you.
Anyways, back at the terminal, there are a lot of "enable" configs. They're all related... but slightly different. For example, enable_swagger
really refers to the OpenAPI documentation. Remember that's the JSON document that powers the Swagger and ReDoc API docs. Then, these are whether or not we want to show those two types of documentation frontends. And down here, enable_entrypoint
and enable_docs
control whether or not certain routes are added to our app.
I bet that didn't completely make sense, so let's play with this. Pretend that we want to disable the docs entirely. Ok! Open config/packages/api_platform.yaml
and, to start, add enable_docs: false
:
api_platform: | |
... lines 2 - 7 | |
enable_docs: false |
As soon as you do that and refresh... alright! Our API documentation is gone... but with a 500 error. When you enable_docs: false
, it literally removes the route to our documentation.
Let's back up. Going to /api
was always kind of a shortcut to get to the docs. The real path was /api/docs
, /api/docs.json
or .jsonld
. And these are now all 404's because we disabled that route. So yay our documentation is gone!
However, when you go to /api
, this actually isn't a documentation page. This is known as the "entry point": it's our API homepage. This page does still exist... but it tries to link to our API docs... which don't exist, and it explodes.
To disable the entry point, move over and add enable_entrypoint:
false:
api_platform: | |
... lines 2 - 8 | |
enable_entrypoint: false |
Now going to /api
give us... beautiful! A 404.
Ok, so we know we can go to /api/treasures.json
or .jsonld
. But what if we just go to /api/treasures
? That... unfortunately is a 500 error! When our browser makes a request, it sends an Accept
header that says that we want HTML. So we're asking our API for the html
version of the treasures. And the html
version is... the documentation. So it tries to link to the documentation and explodes.
To disable this, we can communicate to the system that we don't have Swagger or API documentation at all... so it should stop trying to link to it. Do that by setting enable_swagger: false
:
api_platform: | |
... lines 2 - 9 | |
enable_swagger: false |
Though... that just trades for another 500 error that says:
Hey, you can't enable Swagger UI without enabling Swagger!
Fix that with enable_swagger_ui: false
:
api_platform: | |
... lines 2 - 10 | |
enable_swagger_ui: false |
And now... closer!
Serialization for the format
html
is not supported.
The problem is that we're still requesting the html
version of this resource. But now that we don't have any documentation, our API is like:
Um... not really sure how to return an HTML version of this.
And the truth is: if we totally disable our docs, we don't need an HTML format anymore! And so, we can disable it. Do that by, very simply, removing html
from formats
:
api_platform: | |
formats: | |
jsonld: [ 'application/ld+json' ] | |
json: [ 'application/json' ] | |
jsonhal: [ 'application/hal+json' ] | |
... lines 7 - 10 |
And... we actually have one other spot where we need to do that: in src/Entity/DragonTreasure.php
. When we added our custom csv
format... let's see here it is... we repeated all the formats including html
. So take html
off of there as well:
... lines 1 - 26 | |
( | |
... lines 28 - 40 | |
formats: [ | |
'jsonld', | |
'json', | |
'jsonhal', | |
'csv' => 'text/csv', | |
], | |
... lines 47 - 53 | |
) | |
... lines 55 - 72 | |
class DragonTreasure | |
{ | |
... lines 75 - 232 | |
} |
When we refresh now... got it! Since there's no HTML format, it defaults to JSON-LD
. Our docs are now totally disabled.
Oh, and to disable the docs just for production, I would create an environment variable - like ENABLE_API_DOCS
- then reference that in my config:
Tip
Actually, due to how the config is loaded, environment variables won't work here! Instead, you could disable docs in production only, via:
when@prod:
api_platform:
enable_swagger_ui: false
# config/packages/api_platform.yaml
api_platform:
enable_swagger_ui: '%env(bool:ENABLE_API_DOCS)%'
But... I do like the documentation, so I'm going to undo this change... and this change as well to get our docs back.
api_platform: | |
formats: | |
jsonld: [ 'application/ld+json' ] | |
json: [ 'application/json' ] | |
html: [ 'text/html' ] | |
jsonhal: [ 'application/hal+json' ] | |
# enable_docs: false | |
# enable_entrypoint: false | |
# enable_swagger: false | |
# enable_swagger_ui: false |
... lines 1 - 26 | |
( | |
... lines 28 - 40 | |
formats: [ | |
'jsonld', | |
'json', | |
'html', | |
'jsonhal', | |
'csv' => 'text/csv', | |
], | |
... lines 48 - 54 | |
) | |
... lines 56 - 73 | |
class DragonTreasure | |
{ | |
... lines 76 - 233 | |
} |
Love it!
Next, let's have a fireside chat about authentication. You have a fancy API: do you need API tokens? Or something else?
Hey @Oleh-K!
Ah, you're right! I was assuming too much! The APIPlatform Symfony integration references those variables at compile time (like you said). That would need to be fixed inside API Platform, but actually, I think it's not reasonably fixable. By setting, for example, enable_swagger
to false
, a set of services is removed from the container (which is good - no reason to have those extra service around if they're not used). It would be a decent bit of work to allow this config to use environment variables, and the end result is that people who do want to disable them would still have these extra services "available" in the container, even though they're not used. Not a huge deal, but also probably a good reason not to "fix it".
Anyway, I appreciate you pointing this out! I'll add a note to the course.
Cheers!
Hello!
I have a question about how you did the initial login, since it appears created directly in the video, are you creating it through make:controller login? If not, could I create it this way?
Hey @Fran!
At the start of this tutorial, the frontend and login stuff is pretty simple. It's a MainController::homepage()
that renders main/homepage.html.twig
(and that controller is dead-simple). The template itself is pretty much empty except that it renders a Vue app, which renders the login form. All of that was created by hand. The controller and template and very simple and small (you could definitely use make:controller
to get this), but I created the Vue app by hand.
In a normal Symfony app, I would probably build my login form directly in PHP & Twig. For that, I'd use make:auth
and choose the "login form" option. That will generate you the controller & template for the login form + a few other things.
Does that help? Let me know!
Cheers!
Short question, the editor in use is Phpstrorm? Is this a special skin?
Hey @Klaus-M
Yes, it is PhpStorm, and I believe Ryan uses the "Atom Material Icons" plugin to enhance his editor's theme
Cheers!
Hey @pasquale_pellicani ,
I'm not sure I understand the question :)
I also ask the same question here
What who else is asking here and what exactly? I see only your comment on this page :)
But in case you're looking for part 1, here it is: https://symfonycasts.com/screencast/api-platform .
Cheers!
Thank you very much, it would be ideal to change the title of the courses with part 1 and part 2 because I had difficulty understanding the order of the two courses. I take the opportunity to thank you for the excellent work done ;)
Hey @pasquale_pellicani ,
I see, yeah, it might not be clear enough. I'd try to add cross-link to this course. Also, you can always can look at the track to find the related courses and the correct order: https://symfonycasts.com/tracks/rest#api-platform-3
I hope this helps!
Cheers!
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^3.0", // v3.1.2
"doctrine/annotations": "^2.0", // 2.0.1
"doctrine/doctrine-bundle": "^2.8", // 2.8.3
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
"doctrine/orm": "^2.14", // 2.14.1
"nelmio/cors-bundle": "^2.2", // 2.2.0
"nesbot/carbon": "^2.64", // 2.66.0
"phpdocumentor/reflection-docblock": "^5.3", // 5.3.0
"phpstan/phpdoc-parser": "^1.15", // 1.16.1
"symfony/asset": "6.2.*", // v6.2.5
"symfony/console": "6.2.*", // v6.2.5
"symfony/dotenv": "6.2.*", // v6.2.5
"symfony/expression-language": "6.2.*", // v6.2.5
"symfony/flex": "^2", // v2.2.4
"symfony/framework-bundle": "6.2.*", // v6.2.5
"symfony/property-access": "6.2.*", // v6.2.5
"symfony/property-info": "6.2.*", // v6.2.5
"symfony/runtime": "6.2.*", // v6.2.5
"symfony/security-bundle": "6.2.*", // v6.2.6
"symfony/serializer": "6.2.*", // v6.2.5
"symfony/twig-bundle": "6.2.*", // v6.2.5
"symfony/ux-react": "^2.6", // v2.7.1
"symfony/ux-vue": "^2.7", // v2.7.1
"symfony/validator": "6.2.*", // v6.2.5
"symfony/webpack-encore-bundle": "^1.16", // v1.16.1
"symfony/yaml": "6.2.*" // v6.2.5
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
"mtdowling/jmespath.php": "^2.6", // 2.6.1
"phpunit/phpunit": "^9.5", // 9.6.3
"symfony/browser-kit": "6.2.*", // v6.2.5
"symfony/css-selector": "6.2.*", // v6.2.5
"symfony/debug-bundle": "6.2.*", // v6.2.5
"symfony/maker-bundle": "^1.48", // v1.48.0
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/phpunit-bridge": "^6.2", // v6.2.5
"symfony/stopwatch": "6.2.*", // v6.2.5
"symfony/web-profiler-bundle": "6.2.*", // v6.2.5
"zenstruck/browser": "^1.2", // v1.2.0
"zenstruck/foundry": "^1.26" // v1.28.0
}
}
About environment varibale to disable docs (at 7:56).
As far as i know it is not possible for now, as
api_platform
config loaded during a compile time. So it is has not picked up ENV variables, and next configuration does not work:My current sollution, is:
So if you know the solution how to do that with Environment varibales. Please share.