Fix package type query parameter for V3 search, add capability check#7395
Fix package type query parameter for V3 search, add capability check#7395liliankasem wants to merge 2 commits into
Conversation
PackageSearchResourceV3 was sending the package type filter using the legacy 'packageTypeFilter' query parameter. The SearchQueryService/3.5.0 specification uses 'packageType'. This meant SearchFilter.PackageTypes was silently ignored by nuget.org and other compliant V3 sources. Changes: * Send 'packageType=' (single value) instead of 'packageTypeFilter='. * Detect capability via the SearchQueryService/3.5.0 service-index entry. When SearchFilter.PackageTypes is set on a source that does not advertise this resource, throw NotSupportedException instead of returning unfiltered results that the caller assumes are filtered. * Route filtered queries only to capable endpoints; fall back to all endpoints when no filter is requested. Scope notes (deferred to follow-up work): * SearchFilter.PackageTypes is left as IEnumerable<string> for now to avoid a breaking public API change. Only the first value is sent, matching the protocol contract. * Local source (LocalPackageSearchResource) package type filtering is not addressed here. Refs: NuGet#5991, NuGet/Home#8915
Use TempApiKeyRequestTimeoutInSeconds (10s) instead of 5s, matching the fix applied to sibling tests in NuGet#7390 to address TaskCanceledException under CI load.
|
Thanks @martinrrm! Do you mind reapproving? I just fixed the unit test. |
nkolev92
left a comment
There was a problem hiding this comment.
Sorry for the delay review.
@NuGet/nuget-client It'd be great to get some more thoughts on the behavior for search resources with package type.
| { | ||
| } | ||
|
|
||
| internal PackageSearchResourceV3(HttpSource client, IEnumerable<Uri> searchEndpoints, IEnumerable<Uri> packageTypeCapableEndpoints) |
There was a problem hiding this comment.
Just keep one internal constructor. Especially since we're supporting passing an empty/null anyways.
Likely just the tests need changed
|
|
||
| if (packageTypeFilterRequested && _packageTypeCapableEndpoints.Count == 0) | ||
| { | ||
| throw new NotSupportedException(Strings.Protocol_PackageTypeFilterNotSupported); |
There was a problem hiding this comment.
I know @zivkan requested this, but this behavior makes me wonder what we would do in the case of multi feed search.
I am trying to think forward about how we'd be shaping the API if something like compat is added to the search query.
It also doesn't really provide a means to figure out whether package type filtering is supported when you have that object, so now you have to effectively account for that exception at all times. I think that was part 2 of the feedback.
I'm honestly not sure if we have a great shape for that API right now.
We'd probably want something generic rather than IsPackageTypeFiltering supported or anything like that.
There was a problem hiding this comment.
Also, if we're establishing a precedent of throwing when package type is unsupported, which is an ABI breaking change which I'm not too worried about, I think we'd need to make sure all of the implementers of PackageSearchResource actually have the same behavior.
| // SearchQueryService/3.5.0 specifies a single 'packageType' parameter. | ||
| // We send the first value; passing more than one is a caller error | ||
| // (the protocol does not define multi-value semantics). | ||
| queryString += "&packageType=" + filters.PackageTypes.First(); |
There was a problem hiding this comment.
If that's an unknown syntax, I think we should actually throw in this case.
| _client = client ?? throw new ArgumentNullException(nameof(client)); | ||
| _searchEndpoints = searchEndpoints?.ToArray() ?? throw new ArgumentNullException(nameof(searchEndpoints)); | ||
| _packageTypeCapableEndpoints = packageTypeCapableEndpoints == null | ||
| ? new HashSet<Uri>() |
There was a problem hiding this comment.
Can we make _packageTypeCapableEndpoints nullable so we aren't allocating a HashSet<T> in the "legacy" code path?
private readonly HashSet<Uri>? _packageTypeCapableEndpoints| ? new HashSet<Uri>() | |
| ? null |
Or we can store it as a ICollection<T>, set it to Array.Empty<T>(), and use .Distinct() on the IEnumerable<T> that's passed in here which under the covers creates a HashSet<T> for us? Ideally the input parameter should probably be IReadOnlyList<Uri> so we can call .Count to make a hashset that doesn't need to be resized? Do we deduplicate in other code paths?
| <value>The source does not have the 'version' property.</value> | ||
| </data> | ||
| <data name="Protocol_PackageTypeFilterNotSupported" xml:space="preserve"> | ||
| <value>The source does not advertise a 'SearchQueryService/3.5.0' resource and therefore does not support filtering search results by package type.</value> |
There was a problem hiding this comment.
| <value>The source does not advertise a 'SearchQueryService/3.5.0' resource and therefore does not support filtering search results by package type.</value> | |
| <value>The source does not support filtering search results by package type.</value> |
Not sure if the message needs to include such verbose information like the remedy. Also, would it make sense to include the URI of the feed in the message?
Bug
Fixes: NuGet/Home#8915
Related (closed) prior attempt: #5991
Description
PackageSearchResourceV3was sending the package-type filter using the legacypackageTypeFilterquery parameter. TheSearchQueryService/3.5.0specification usespackageType. As a result,SearchFilter.PackageTypeshas been silently ignored by nuget.org and other compliant V3 sources for as long as the property has existed publicly.This PR is intentionally scoped to the bug fix plus capability detection. The broader API redesign and local-source support discussed in #5991 are deferred to follow-up issues so this PR can land without re-litigating the same design conversation.
What this PR does
packageType=(single value) instead ofpackageTypeFilter=.SearchQueryService350entry is fetched separately. WhenSearchFilter.PackageTypesis set on a source that does not advertiseSearchQueryService/3.5.0, the resource throwsNotSupportedExceptioninstead of silently returning unfiltered results that the caller assumes are filtered. This addresses the primary concern raised by @zivkan in Add support for package type queries in both local and remote sources #5991.What this PR explicitly does NOT do (and why)
SearchFilter.PackageTypes(IEnumerable<string>→string)LocalPackageSearchResourceNotSupportedExceptiongives the front-end a clean signal to skip non-capable sources.Behavior change
Callers who previously set
SearchFilter.PackageTypesagainst a V3 source that does not advertiseSearchQueryService/3.5.0used to get unfiltered results (silently broken). They will now get aNotSupportedException. This is a strict correctness improvement: the caller's intent was never being honoured before, and now they get an explicit signal.PR Checklist