-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpClient] Add a ConditionalHttpClient #30592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
8223b4d
to
eaf6bb7
Compare
src/Symfony/Component/HttpClient/Tests/CurlConditionalHttpClientTest.php
Outdated
Show resolved
Hide resolved
@XuruDragon I appreciate your contribution to Symfony ... but to be completely honest, I don't like the idea behind this proposal. If your app is complex enough to have lots of different sets of requests, you can already configure multiple clients to use the most appropriate one. I can't see a common-enough use case for this feature. @XuruDragon sorry if I'm being too honest 😅 .. and of course, thanks again for helping Symfony with your contributions! |
Hi @javiereguiluz I understand what you means. Imagine that you have to send a request to a server that, on the same domain name / url, has an API on "/api" and a website on "/land" that you want to explore (I do not know why, but suppose that is the case). But this API is in JSON and the website is not ... I do not know if I expressed myself well? |
Hi @XuruDragon, Did you have a case where you needed something like this? I never had one and I really never had a case where I needed to access some external API and their Website. Is just imagining an edge case like this enough to add this Client? |
Hi @kunicmarko20, |
💯 this - this also spans to security strengthening: when configuring a client with default credentials, nothing guarantees that the consumer will use the client with the expected target host/URL right now. This means that if you configure defaults with some bearer for foo.com but the consumer hits bar.com instead, the bearer is sent to bar.com. |
But if you have a bearer for foo.com and not for bar.com, you make requests to bar.com with the default HTTP client and requests to foo.com with a client defined for it and with the bearer token defined as a config option. What I mean is that we already have a solution for this problem: different clients with different config options. Here we'd introduce a slightly different mechanism: different options with the same client depending on the URL 😕 |
@javiereguiluz that's putting a lot of responsibility on the shoulder of users - and how is dealing with one instance (like this PR allows) supposed to be simpler than juggling with two of them in userland? Here, this client acts as a router: based on the URL, it decides which credentials/etc should be used. |
With a very basic comparaison : |
@XuruDragon but this is not how existing Symfony features work. When you have different cache configs, you define 2 or more cache pools ... you don't define 1 pool with different configs based on a regexp applied to the cache key. When you have different log configs, you define 2 or more log handlers ... you don't define 1 handler with different configs based on a regexp applied to the lgo channel or message. The same happens everywhere: Messenger, Serializer, Lock, etc. We always define N "clients" for them, not 1 client with a regexp-based discriminator. |
@javiereguiluz here is the difference: log/cache/message buses all need several transports. HTTP doesn't: there is only one single WWW. Its routing layer is universal. Having one single HTTP client with a router on top is much more aligned to the web, and also much more DX. (ie there's one client and management of credentials is centralized, consumers don't need to care). |
4b3e4e2
to
a1b5933
Compare
This has also the advantage for concurrent calls. I might be mistaken but there is a multi curl resource per client. Which means with 2 clients we can't get proper advantage of it. Currently with Guzzle for example if we need to call 2 independent api's we will end up creating 2 api's until we decide to optimise the 2 calls. We had such an issue quite recently and ended up having to use a single client and it's not that pretty. I think this idea is great and can be made even greater. |
@oliverde8 💯 ! I forgot to mention it and you're perfectly right. A single client maximizes the reuse of existing connections and maximizes concurrency monitoring. |
Thanks @oliverde8. |
Just thinking, having a single client for multiple api's have it's issues; mainly for authorization.
Why not pass list of objects, RequestEnricherInterfaces with 2 methods Not sure if it's a good idea, or over complicated |
Isnt it as easy to handle this type of business logic in a custom decorator? Would be much more explicit isnt it, and eventually more flexible. Is the generic feature really a must? Do we aim for some framework config integration? Which might define N clients 🤔 edit: what about supporting a |
6bc396e
to
65d08a7
Compare
7432f9b
to
1fed2f6
Compare
9b66a31
to
7a1a8a0
Compare
Now that #30654 is merged, this one should probably be rebased (and adapter). |
This PR was merged into the 4.3-dev branch. Discussion ---------- [HttpClient] Add a ScopingHttpClient | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This PR is a follow up of #30592 by @XuruDragon, with two main differences: - I think `ScopingHttpClient` might be a better name for what is called a `ConditionalHttpClient` there, - the `FrameworkBundle` part is removed so that it can be submitted separately later on. With a `ScopingHttpClient`, you can add some default options conditionally based on the requested URL and a regexp that it should match. This allows building clients that add e.g. credentials based on the requested scheme/host/path. When the requested URL is a relative one, a default index can be provided - whose corresponding default options (the `base_uri` one especially) will be used to turn it into an absolute URL. Regexps are anchored on their left side. E.g. this defines a client that will send some github token when a request is made to the corresponding API, and will not send those credentials if any other host is requested, while also turning relative URLs to github ones: ```php $client = HttpClient::create(); $githubClient = new ScopingClient($client, [ 'http://api\.github\.com/' => [ 'base_uri' => 'http://api.github.com/', 'headers' => ['Authorization: token '.$githubToken], ], ], 'http://api\.github\.com/'); ``` Of course, it's possible to define several regexps as keys so that one can create a client that is authenticated against several hosts/paths. Commits ------- 1ee0a11 [HttpClient] Add a ScopingHttpClient
7a1a8a0
to
1d16850
Compare
I continued the framework-bundle part in #30674 |
Adding a new client
ConfitionalHttpClient
to the newHttpClient
component.This class is intended to allow different options to be sent based on a regexp executed on the url of the request. In simple words : Auto-configure the default options based on the requested URL.
This class implement the
HttpClientInterface
interfaceThe first regexp that math the url win.
Its first parameter expects an object implementing the
HttpClientInterface
interfaceThe second parameter is an array, of default options to use when the regexp provided as key matches the requested URL, to be given to the
HttpClientInterface request
method.Here is an example of how to use this class :