SmooAI.Fetch
3.3.4
dotnet add package SmooAI.Fetch --version 3.3.4
NuGet\Install-Package SmooAI.Fetch -Version 3.3.4
<PackageReference Include="SmooAI.Fetch" Version="3.3.4" />
<PackageVersion Include="SmooAI.Fetch" Version="3.3.4" />
<PackageReference Include="SmooAI.Fetch" />
paket add SmooAI.Fetch --version 3.3.4
#r "nuget: SmooAI.Fetch, 3.3.4"
#:package SmooAI.Fetch@3.3.4
#addin nuget:?package=SmooAI.Fetch&version=3.3.4
#tool nuget:?package=SmooAI.Fetch&version=3.3.4
SmooAI.Fetch
HTTP that gets out of your way for .NET 8+ — typed JSON in and out, automatic retry on transient failures, auth token injection, one error type for every non-2xx.
.NET port of @smooai/fetch. Stop writing the same retry/backoff/auth wrapper for every API client in every service. Wire-compatible semantics with the TypeScript, Python, Go, and Rust ports.
Install
dotnet add package SmooAI.Fetch
What you get
- Typed JSON —
GetAsync<User>andPostAsync<Dto, User>. Your request and response shapes, strongly typed. NoJsonSerializer.Deserializeboilerplate on every call site. - Automatic retries on transient failures — network blips, timeouts, and
408/425/429/5xxresponses are retried with exponential backoff + jitter. Retry-Afteris honored — when a server tells you "wait 5s", the client waits 5s instead of your default backoff. Never eat a 429 again.- Async auth tokens — register an
AuthTokenProvideronce; every request picks up a fresh bearer token without restartingHttpClient. - One typed error per non-2xx — catch
HttpResponseErrorand you've got status, body, headers, URI, and method on one exception. - Per-request cancellation + timeout — linked
CancellationTokenSourceunder the hood; every method takes aCancellationToken. - DI-ready —
AddSmooFetch(options => …)plugs intoIHttpClientFactoryand yourIServiceCollection.
Quick start — standalone
using SmooAI.Fetch;
var fetch = SmooFetch.Create(options =>
{
options.BaseUrl = "https://api.example.com";
options.Timeout = TimeSpan.FromSeconds(30);
options.RetryPolicy = RetryPolicy.ExponentialBackoff(maxRetries: 3);
options.AuthTokenProvider = async ct => await GetBearerTokenAsync(ct);
});
var me = await fetch.GetAsync<User>("/users/me");
var created = await fetch.PostAsync<CreateUserDto, User>("/users", dto);
Quick start — DI / IHttpClientFactory
builder.Services.AddSmooFetch(options =>
{
options.BaseUrl = builder.Configuration["Api:BaseUrl"];
options.RetryPolicy = RetryPolicy.ExponentialBackoff(maxRetries: 3);
options.AuthTokenProvider = _ => Task.FromResult<string?>(bearerToken);
});
// Inject wherever you need it
public class BillingService(SmooFetch fetch)
{
public Task<Invoice> GetInvoice(string id) =>
fetch.GetAsync<Invoice>($"/invoices/{id}");
}
Retry policy — honors Retry-After
options.RetryPolicy = RetryPolicy.ExponentialBackoff(
maxRetries: 3,
initialDelay: TimeSpan.FromMilliseconds(250),
maxDelay: TimeSpan.FromSeconds(10),
backoffFactor: 2.0,
jitter: true);
- Retries on transient exceptions (timeouts, socket errors) and on
408/425/429/500/502/503/504. - Honors the
Retry-Afterheader on429/503— if the server says "wait 5s", the client waits 5s instead of your backoff. - Exponential backoff with jitter; bounded by
maxDelay.
Typed errors — one catch per layer
try
{
var user = await fetch.GetAsync<User>("/users/me");
}
catch (HttpResponseError ex)
{
// ex.StatusCode — int
// ex.Body — string (response body)
// ex.Headers — HttpResponseHeaders
// ex.RequestUri — Uri
// ex.Method — HttpMethod
}
HttpResponseError is thrown for every non-2xx response. Transient exceptions (timeouts, socket resets) surface as their original type if retries are exhausted.
Async auth token provider
Auth is fetched per request via AuthTokenProvider: async ct => … — pair this with a cached/rotating token source and every call gets a fresh Authorization header without re-registering the client.
options.AuthTokenProvider = async ct =>
{
var token = await _tokenCache.GetOrRefreshAsync(ct);
return token; // null => no Authorization header on this request
};
Cancellation + per-request timeout
Every method accepts a CancellationToken. The configured Timeout creates a linked CancellationTokenSource under the hood:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var user = await fetch.GetAsync<User>("/users/me", cancellationToken: cts.Token);
Related
@smooai/fetch— TypeScript / Nodesmooai-fetch— Rustsmooai-fetch— Pythongithub.com/SmooAI/fetch/go/fetch— Go
License
MIT — © SmooAI
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Http.Polly (>= 8.0.11)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Polly (>= 8.5.0)
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Http.Polly (>= 8.0.11)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Polly (>= 8.5.0)
-
net9.0
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Http.Polly (>= 8.0.11)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Polly (>= 8.5.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.3.4 | 94 | 4/24/2026 |