11.
How Sub-Requests Work
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.
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Whoops, an error! Please, try again later.
10 Comments
It's been lovely!
One question, what if there would be an inheritance mechanism for sub-Request , all bags and keys populated from master at the very beginning (btw, it really is done in some part (User-Agent)), then changing by schedule?
All stuff, which are to be added\overridden would be added\overridden(_controller, may be something else), as sub-Request goes with different events through different listeners. Who can prevent? Why should we get rid of information, which already have and which may be useful and utilized by sub-Request without extra manipulation? In context of our case, for example, we wouldn't need to put in this redundant:
{'userOnMac': app.request.attributes.get('isMac').
Hi Andrew!
Wow, this is a *very* insightful question! In truth, *some* information is shared from the master request to the sub-request: https://github.com/symfony/.... I'm honestly not sure why *some* things are copied to the sub-request, but other things are not. However, there is a very good reason why information should *not* be shared from the master request to the sub-request (and why you should ignore any information that *is* shared). The main purpose of sub-requests is to enable ESI HTTP Caching (which is not something we cover in this tutorial). With ESI, instead of having a master request and a sub-request, there are literally *two* completely independent, externally-originated master requests made (one for the whole page, and one for just the "embedded" controller part). By not sharing information between the master and sub requests, you allow yourself to take advantage of ESI caching (which is very powerful) if you want to (without really changing anything in your code).
Does that help? You were very smart to think about this!
You've mentioned how to work with sub-requests, but you haven't described why it is useful to distinguish master requests from sub requets - why does the HttpKernelInterface have this distinction at all?
In that case, shame on me! Yes, this is a very good question.
Basically, there are certain things (event listeners) that only make sense on the master request. For example: suppose you have a listener that changes that if the URL starts with /admin, and the user doesn't have ROLE_ADMIN, deny them access (there are easier ways to do this than a listener, but you get the idea). This *only* needs to be done on the master request. It may be "ok" to check this on the sub-request as well, but its redundant: there's no way someone could have made it into your site at all if this check failed on the master request (so why check it again). More abstractly, anything that checks some information on the real request probably shouldn't run on the sub-request.
There's also one other (practical situation). Sometimes people execute listeners in order to "setup" something in their system - e.g. add some analytics because a "mobile" user is accessing the site. In this case, if you run this listener again on sub-requests, you may double-count the analytic. So again, abstractly: when your listener does something that *must* only happens once per "real" request, it's important to know if you're a master/sub-request.
I work with a company that users a lot of listeners, and for a long time they didn't know about this master/sub-request thing (their listeners ran in all cases). Eventually, some edge-cases started causing weird bugs because they didn't expect the listeners to be called multiple times.
I hope that helps!
I keep looking for an answer to this but I can't find any.
Is there a significant difference between master/sub requests strictly from a performance point-of-view ? When making a sub-request, my thinking is that it should be significantly faster because the bundles are already loaded, the container already instatiated most services that are needed and-so-on. I'm curious if you know of some benchmark published somewhere about this.
Hi Radu!
Yes, you're right - a sub-request is faster than a master request because of the exact reason you just said: the container is instantiated and so are most services. I don't know of any benchmarks about this, but *how* much faster will vary based on how many new (previously uninstantiated) services you request on a sub-request. Also, even though all the listeners are called again, most of them do not actually do anything on sub-requests and return very quickly.
If you look at the Performance / Timeline tab of the profiler on a page that has sub-requests, you'll be able to easily see how much faster each sub-request is than the main request :).
Anyways - good question, and you already are thinking correctly about the answer! But, sub-requests are still fairly "heavy", so use them cautiously, unless you're planning on caching them with ESI (then use them liberally!)
Cheers!
I think I still need to do some research but I think with subrequests I can solve the following problem (of course using the classic blog example):
Assume I have an API that listens to '/users/{id}/posts' to return the posts from user with given id. Now if I want to get the posts of the currently authenticated user I would need to send a request to '/users/{id}/posts' where id is the id of the currently authenticated user. I think this is weird. I'm already authenticated and the webserver should be able to figure out my id. (do you agree?)
So, I think I would want an endpoint '/posts' that returns all the posts from the currently authenticated user (agree?). So, in this second controller method I could create a new subrequest pointing to '/users/{id}/posts' where {id} is the id of the currently authenticated user (derived from the JWT token for example). Then I can return the response of that subrequest as the response of the main request. This way I don't need to duplicate the logic used in the controller method listening to '/users/{id}/posts'.
What do you think?
Ok, I think I found a simpler solution. I found out you can just map multiple URLs to one controller action so I can do something like this:
Hey Johan!
Yes, I like your simpler solution a lot :). And this is a fairly common type of thing to do. Technically, it's not RESTful... because it means that if I authenticate as user A and go to /posts I will get a different "resource" than if I authenticate as user B and also go to /posts... but I think that's really not that important :). Facebook's API does this a lot - you can go to "/me" to get info about "my" user.
To summarize: I love your solution for this in Symfony, and I also support what you're doing in the API, even if some people will grip that it's not technically RESTful. If it's useful and sane, go for it.
Cheers!
Alright, thank you. Ye, I think I would prefer this simple but not so RESTful approach over the more complicated but RESTful approach.
Rules are made to be broken, right? ;)
Thank you for response, it is very much appreciated.
"Houston: no signs of life"
Start the conversation!