Skip to content

Commit 059662e

Browse files
authored
[Client SDK] Improve ergonomics (loic-sharma#339)
* Simplifies search APIs on `NuGetClient` * Makes it a little easier to create a `CatalogProcessor`
1 parent 61c288a commit 059662e

File tree

5 files changed

+103
-41
lines changed

5 files changed

+103
-41
lines changed

docs/tools/sdk.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,10 @@ Search for "json" packages:
7777

7878
```csharp
7979
NuGetClient client = new NuGetClient("https://api.nuget.org/v3/index.json");
80-
SearchResponse response = await client.SearchAsync("json");
80+
IReadOnlyList<SearchResult> results = await client.SearchAsync("json");
8181

82-
Console.WriteLine($"Found {response.TotalHits} total results");
83-
84-
foreach (SearchResult searchResult in response.Data)
82+
foreach (SearchResult result in results)
8583
{
86-
Console.WriteLine($"Found package {searchResult.Id} {searchResult.Version}");
84+
Console.WriteLine($"Found package {result.PackageId} {searchResult.Version}");
8785
}
8886
```

samples/Sample02_Search.cs

+10-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Threading.Tasks;
34
using BaGet.Protocol.Models;
45
using Xunit;
@@ -12,18 +13,16 @@ public async Task Search()
1213
{
1314
// Search for packages that are relevant to "json".
1415
NuGetClient client = new NuGetClient("https://api.nuget.org/v3/index.json");
15-
SearchResponse response = await client.SearchAsync("json");
16-
17-
Console.WriteLine($"Found {response.TotalHits} results");
16+
IReadOnlyList<SearchResult> results = await client.SearchAsync("json");
1817

1918
var index = 1;
20-
foreach (SearchResult searchResult in response.Data)
19+
foreach (SearchResult result in results)
2120
{
2221
Console.WriteLine($"Result #{index}");
23-
Console.WriteLine($"Package id: {searchResult.PackageId}");
24-
Console.WriteLine($"Package version: {searchResult.Version}");
25-
Console.WriteLine($"Package downloads: {searchResult.TotalDownloads}");
26-
Console.WriteLine($"Package versions: {searchResult.Versions.Count}");
22+
Console.WriteLine($"Package id: {result.PackageId}");
23+
Console.WriteLine($"Package version: {result.Version}");
24+
Console.WriteLine($"Package downloads: {result.TotalDownloads}");
25+
Console.WriteLine($"Package versions: {result.Versions.Count}");
2726
Console.WriteLine();
2827

2928
index++;
@@ -35,15 +34,11 @@ public async Task Autocomplete()
3534
{
3635
// Search for packages whose names' start with "Newt".
3736
NuGetClient client = new NuGetClient("https://api.nuget.org/v3/index.json");
38-
AutocompleteResponse response = await client.AutocompleteAsync("Newt");
39-
40-
Console.WriteLine($"Found {response.TotalHits} results");
37+
IReadOnlyList<string> packageIds = await client.AutocompleteAsync("Newt");
4138

42-
var index = 1;
43-
foreach (string packageId in response.Data)
39+
foreach (string packageId in packageIds)
4440
{
45-
Console.WriteLine($"Found package ID #{index}: '{packageId}'");
46-
index++;
41+
Console.WriteLine($"Found package ID '{packageId}'");
4742
}
4843
}
4944
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using BaGet.Protocol.Catalog;
4+
using Microsoft.Extensions.Logging;
5+
6+
namespace BaGet.Protocol
7+
{
8+
public static class NuGetClientFactoryExtensions
9+
{
10+
/// <summary>
11+
/// Create a new <see cref="CatalogProcessor"/> to discover and download catalog leafs.
12+
/// Leafs are processed by the <see cref="ICatalogLeafProcessor"/>.
13+
/// </summary>
14+
/// <param name="clientFactory">The factory used to create NuGet clients.</param>
15+
/// <param name="cursor">Cursor to track succesfully processed leafs. Leafs before the cursor are skipped.</param>
16+
/// <param name="leafProcessor">The leaf processor.</param>
17+
/// <param name="options">The options to configure catalog processing.</param>
18+
/// <param name="logger">The logger used for telemetry.</param>
19+
/// <param name="cancellationToken">A token to cancel the task.</param>
20+
/// <returns>The catalog processor.</returns>
21+
public static async Task<CatalogProcessor> CreateCatalogProcessorAsync(
22+
this NuGetClientFactory clientFactory,
23+
ICursor cursor,
24+
ICatalogLeafProcessor leafProcessor,
25+
CatalogProcessorOptions options,
26+
ILogger<CatalogProcessor> logger,
27+
CancellationToken cancellationToken = default)
28+
{
29+
var catalogClient = await clientFactory.CreateCatalogClientAsync(cancellationToken);
30+
31+
return new CatalogProcessor(
32+
cursor,
33+
catalogClient,
34+
leafProcessor,
35+
options,
36+
logger);
37+
}
38+
}
39+
}

src/BaGet.Protocol/NuGetClient.cs

+48-16
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,14 @@ public virtual async Task<PackageMetadata> GetPackageMetadataAsync(string packag
254254
/// </param>
255255
/// <param name="cancellationToken">A token to cancel the task.</param>
256256
/// <returns>The search results, including prerelease packages.</returns>
257-
public virtual async Task<SearchResponse> SearchAsync(string query = null, CancellationToken cancellationToken = default)
257+
public virtual async Task<IReadOnlyList<SearchResult>> SearchAsync(
258+
string query = null,
259+
CancellationToken cancellationToken = default)
258260
{
259261
var client = await _clientFactory.CreateSearchClientAsync(cancellationToken);
262+
var response = await client.SearchAsync(query, cancellationToken: cancellationToken);
260263

261-
return await client.SearchAsync(query, cancellationToken: cancellationToken);
264+
return response.Data;
262265
}
263266

264267
/// <summary>
@@ -270,14 +273,18 @@ public virtual async Task<SearchResponse> SearchAsync(string query = null, Cance
270273
/// <param name="includePrerelease">Whether to include prerelease packages.</param>
271274
/// <param name="cancellationToken">A token to cancel the task.</param>
272275
/// <returns>The search results.</returns>
273-
public virtual async Task<SearchResponse> SearchAsync(string query, bool includePrerelease, CancellationToken cancellationToken = default)
276+
public virtual async Task<IReadOnlyList<SearchResult>> SearchAsync(
277+
string query,
278+
bool includePrerelease,
279+
CancellationToken cancellationToken = default)
274280
{
275281
var client = await _clientFactory.CreateSearchClientAsync(cancellationToken);
276-
277-
return await client.SearchAsync(
282+
var response = await client.SearchAsync(
278283
query,
279284
includePrerelease: includePrerelease,
280285
cancellationToken: cancellationToken);
286+
287+
return response.Data;
281288
}
282289

283290
/// <summary>
@@ -290,11 +297,20 @@ public virtual async Task<SearchResponse> SearchAsync(string query, bool include
290297
/// <param name="take">The number of results to include.</param>
291298
/// <param name="cancellationToken">A token to cancel the task.</param>
292299
/// <returns>The search results, including prerelease packages.</returns>
293-
public virtual async Task<SearchResponse> SearchAsync(string query, int skip, int take, CancellationToken cancellationToken = default)
300+
public virtual async Task<IReadOnlyList<SearchResult>> SearchAsync(
301+
string query,
302+
int skip,
303+
int take,
304+
CancellationToken cancellationToken = default)
294305
{
295306
var client = await _clientFactory.CreateSearchClientAsync(cancellationToken);
307+
var response = await client.SearchAsync(
308+
query,
309+
skip,
310+
take,
311+
cancellationToken: cancellationToken);
296312

297-
return await client.SearchAsync(query, skip, take, cancellationToken: cancellationToken);
313+
return response.Data;
298314
}
299315

300316
/// <summary>
@@ -308,11 +324,23 @@ public virtual async Task<SearchResponse> SearchAsync(string query, int skip, in
308324
/// <param name="take">The number of results to include.</param>
309325
/// <param name="cancellationToken">A token to cancel the task.</param>
310326
/// <returns>The search results, including prerelease packages.</returns>
311-
public virtual async Task<SearchResponse> SearchAsync(string query, bool includePrerelease, int skip, int take, CancellationToken cancellationToken = default)
327+
public virtual async Task<IReadOnlyList<SearchResult>> SearchAsync(
328+
string query,
329+
bool includePrerelease,
330+
int skip,
331+
int take,
332+
CancellationToken cancellationToken = default)
312333
{
313334
var client = await _clientFactory.CreateSearchClientAsync(cancellationToken);
335+
var response = await client.SearchAsync(
336+
query,
337+
skip,
338+
take,
339+
includePrerelease,
340+
includeSemVer2: true,
341+
cancellationToken);
314342

315-
return await client.SearchAsync(query, skip, take, includePrerelease, includeSemVer2: true, cancellationToken);
343+
return response.Data;
316344
}
317345

318346
/// <summary>
@@ -322,12 +350,15 @@ public virtual async Task<SearchResponse> SearchAsync(string query, bool include
322350
/// The search query. If <see langword="null"/>, gets default autocomplete results.
323351
/// </param>
324352
/// <param name="cancellationToken">A token to cancel the task.</param>
325-
/// <returns>The autocomplete results.</returns>
326-
public virtual async Task<AutocompleteResponse> AutocompleteAsync(string query = null, CancellationToken cancellationToken = default)
353+
/// <returns>The package IDs that matched the query.</returns>
354+
public virtual async Task<IReadOnlyList<string>> AutocompleteAsync(
355+
string query = null,
356+
CancellationToken cancellationToken = default)
327357
{
328358
var client = await _clientFactory.CreateSearchClientAsync(cancellationToken);
359+
var response = await client.AutocompleteAsync(query, cancellationToken: cancellationToken);
329360

330-
return await client.AutocompleteAsync(query, cancellationToken: cancellationToken);
361+
return response.Data;
331362
}
332363

333364
/// <summary>
@@ -339,16 +370,17 @@ public virtual async Task<AutocompleteResponse> AutocompleteAsync(string query =
339370
/// <param name="skip">The number of results to skip.</param>
340371
/// <param name="take">The number of results to include.</param>
341372
/// <param name="cancellationToken">A token to cancel the task.</param>
342-
/// <returns>The autocomplete results.</returns>
343-
public virtual async Task<AutocompleteResponse> AutocompleteAsync(string query, int skip, int take, CancellationToken cancellationToken = default)
373+
/// <returns>The package IDs that matched the query.</returns>
374+
public virtual async Task<IReadOnlyList<string>> AutocompleteAsync(string query, int skip, int take, CancellationToken cancellationToken = default)
344375
{
345376
var client = await _clientFactory.CreateSearchClientAsync(cancellationToken);
346-
347-
return await client.AutocompleteAsync(
377+
var response = await client.AutocompleteAsync(
348378
query,
349379
skip: skip,
350380
take: take,
351381
cancellationToken: cancellationToken);
382+
383+
return response.Data;
352384
}
353385
}
354386
}

src/BaGet.Protocol/readme.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,10 @@ Search for "json" packages:
8383

8484
```csharp
8585
NuGetClient client = new NuGetClient("https://api.nuget.org/v3/index.json");
86-
SearchResponse response = await client.SearchAsync("json");
86+
IReadOnlyList<SearchResult> results = await client.SearchAsync("json");
8787

88-
Console.WriteLine($"Found {response.TotalHits} total results");
89-
90-
foreach (SearchResult searchResult in response.Data)
88+
foreach (SearchResult result in results)
9189
{
92-
Console.WriteLine($"Found package {searchResult.Id} {searchResult.Version}");
90+
Console.WriteLine($"Found package {result.PackageId} {searchResult.Version}");
9391
}
9492
```

0 commit comments

Comments
 (0)