Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JonPurvis
left a comment
There was a problem hiding this comment.
Thanks for this @Cbrad24 馃殌
The connector boots HasApiVersion before the request, so the connector replaces {version} first and the request never gets a chance.
I've left a few comment but nothing too major. If those could be addressed, that'd be great. Regarding a point you made in your PR:
Side note: #564 description lists UrlPath and Subdomain as enum cases, but the merged enum has a single Url case covering both.
This was a very late change made pre merge because UrlPath and Subdomain both involved replacing part of the URL, so we decided to just make one Url case to handle both.
| VersionMode::QueryParam => $pendingRequest->query()->add($this->versionKey, $this->apiVersion), | ||
| VersionMode::Url => $pendingRequest->setUrl( | ||
| str_replace('{version}', $this->ensureVersionIsSafeForUrl($this->apiVersion), $pendingRequest->getUrl()) | ||
| str_replace('{version}', $this->ensureVersionIsSafeForUrl($this->getRequestApiVersion($pendingRequest) ?? $this->apiVersion), $pendingRequest->getUrl()) |
There was a problem hiding this comment.
Small readability tweak: call a resolveUrlApiVersion($pendingRequest) helper here (see my next comment for possible implementation). Same behaviour you鈥檙e going for, we still substitute the request鈥檚 version when the connector boots first, just not inlined as getRequestApiVersion() ?? $this->apiVersion.
| protected function getRequestApiVersion(PendingRequest $pendingRequest): ?string | ||
| { | ||
| $request = $pendingRequest->getRequest(); | ||
|
|
||
| return method_exists($request, 'getApiVersion') ? $request->getApiVersion() : null; | ||
| } |
There was a problem hiding this comment.
Please could you rename this to resolveUrlApiVersion() so it鈥檚 more obvious it鈥檚 for the {version} placeholder, not header/query.
Couple of other suggestions too:
Only look at the request when the connector is booting ($pendingRequest->getConnector() === $this). When the request boots URL mode later, $this is already the request, so we can just use $this->apiVersion.
Only use the request鈥檚 version if the request is also in VersionMode::Url (needs a small getVersionMode() getter on the trait). If someone calls setApiVersion('beta') on a request that鈥檚 still in default Header mode, we should not change the URL path, only the header.
Detect HasApiVersion with Helpers::classUsesRecursive($request) instead of method_exists($request, 'getApiVersion'), so unrelated getApiVersion() methods don鈥檛 affect URLs.
There was a problem hiding this comment.
Something like:
/**
* Resolve which version to substitute into `{version}` for URL mode.
*/
protected function resolveUrlApiVersion(PendingRequest $pendingRequest): string
{
if ($pendingRequest->getConnector() === $this) {
$request = $pendingRequest->getRequest();
if (in_array(self::class, Helpers::classUsesRecursive($request), true)
&& $request->getVersionMode() === VersionMode::Url) {
$requestVersion = $request->getApiVersion();
if (is_string($requestVersion) && $requestVersion !== '') {
return $requestVersion;
}
}
}
return $this->apiVersion;
}Then a getter:
public function getVersionMode(): VersionMode
{
return $this->versionMode;
}|
|
||
| return true; | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Could you add a test for this scenario?
Connector still uses VersionMode::Url with v1, but the request only overrides via header, makeVersionedRequest('beta', VersionMode::Header). Here setApiVersion('beta') must not change the URL; the path should stay https://api.provider.com/v1, and the header should be api-version: beta.
PR #564 introduces a
HasApiVersiontrait for API versioning, including a{version}placeholder in the URL withVersionMode::Url.I tried to use this with Microsoft Graph's API, as its a good fit for switching between Graph's
v1.0andbetaAPIs. The problem I ran into was that withVersionMode::Url, the connector's version always wins when it has one, and$request->setApiVersion()is ignored.This is because the connector boots first and replaces
{version}on its pass, so when the request's plugin boots there is no{version}left to replace:$connector->send($request)creates aPendingRequest{version}.This PR adds a
getRequestApiVersionmethod that tries the request's version before the connector's, so a request wins, as #564's docs describe: "Prefer the request override when only one call should differ." It also adds a test that asserts a request override wins over a connector version.Only
VersionMode::Urlis affected by the boot order, sinceVersionMode::HeaderandVersionMode::QueryParamboth useadd()which replaces the connector's value under the same key.Example failing code:
Side note: #564's description lists
UrlPathandSubdomainas enum cases, but the merged enum has a singleUrlcase covering both.