|
| 1 | +# FluentlyHttpClient — Agent Guide |
| 2 | + |
| 3 | +Fluent HTTP client library for .NET 10 with middleware pipeline, GraphQL support, and response caching. |
| 4 | +**NuGet packages**: `FluentlyHttpClient` (core) | `FluentlyHttpClient.Entity` (SQL-backed caching) |
| 5 | + |
| 6 | +## Commands |
| 7 | + |
| 8 | +```bash |
| 9 | +dotnet restore # Restore dependencies |
| 10 | +dotnet build # Build all projects |
| 11 | +dotnet test # Run all tests (uses test.runsettings) |
| 12 | +dotnet test --filter "FullyQualifiedName~SomeTest" # Run specific tests |
| 13 | +dotnet pack # Pack NuGet packages |
| 14 | +dotnet run --project benchmark/FluentlyHttpClient.Benchmarks.csproj # Benchmarks |
| 15 | +``` |
| 16 | + |
| 17 | +## Project Layout |
| 18 | + |
| 19 | +| Path | Purpose | |
| 20 | +| ---------------------------------------- | -------------------------------------------------------- | |
| 21 | +| `src/FluentlyHttpClient/` | Core library | |
| 22 | +| `src/FluentlyHttpClient.Entity/` | EF Core + SQL Server response caching (optional package) | |
| 23 | +| `test/` | xUnit tests (unit + integration) | |
| 24 | +| `benchmark/` | BenchmarkDotNet microbenchmarks | |
| 25 | +| `samples/FluentlyHttpClient.Sample.Api/` | ASP.NET Core sample API used in integration tests | |
| 26 | + |
| 27 | +## Architecture |
| 28 | + |
| 29 | +### Core Abstractions |
| 30 | + |
| 31 | +- **`IFluentHttpClientFactory`** — singleton registry of named `IFluentHttpClient` instances |
| 32 | +- **`FluentHttpClientBuilder`** — fluent builder for client config (base URL, headers, timeout, middleware) |
| 33 | +- **`FluentHttpRequestBuilder`** — fluent builder for individual requests (method, URI template, query params, body) |
| 34 | +- **`FluentHttpRequest`** / **`FluentHttpResponse`** / **`FluentHttpResponse<T>`** — wrappers around `HttpRequestMessage` / `HttpResponseMessage` |
| 35 | +- **`IFluentHttpMiddleware`** — decorator pipeline interface; implement for cross-cutting concerns |
| 36 | + |
| 37 | +### Middleware Pipeline |
| 38 | + |
| 39 | +Middleware runs in registration order; `ActionExecuteMiddleware` is always the final stage (added internally). |
| 40 | +Each middleware receives `FluentHttpMiddlewareContext` and calls `next(context)` to continue the chain. |
| 41 | + |
| 42 | +``` |
| 43 | +[Logger] → [Timer] → [Cache] → [ActionExecuteMiddleware (sends HTTP)] |
| 44 | + ←──────────────────── response bubbles back ────────────── |
| 45 | +``` |
| 46 | + |
| 47 | +Built-in middleware lives in `src/FluentlyHttpClient/Middleware/` and `src/FluentlyHttpClient/Caching/`. |
| 48 | + |
| 49 | +### Request/Response Context |
| 50 | + |
| 51 | +Both `FluentHttpRequest` and `FluentHttpResponse` implement `IFluentHttpMessageState`, which exposes an `Items` dictionary (`IDictionary<object, object>`). |
| 52 | +Use `Items` to pass data between middleware stages — **do not use static/ambient state**. |
| 53 | + |
| 54 | +### Response Caching |
| 55 | + |
| 56 | +- Default: `MemoryResponseCacheService` (in-memory, registered by `AddFluentlyHttpClient()`) |
| 57 | +- Optional: `RemoteResponseCacheService` (SQL Server via EF Core, registered by `AddFluentlyHttpClientEntity()`) |
| 58 | +- Cache keys are derived from `request.GetHash()` — see `src/FluentlyHttpClient/RequestHashingExtensions.cs` |
| 59 | + |
| 60 | +### DI Registration |
| 61 | + |
| 62 | +```csharp |
| 63 | +// Core — registers IFluentHttpClientFactory, IResponseCacheService (in-memory), IHttpResponseSerializer |
| 64 | +services.AddFluentlyHttpClient(); |
| 65 | + |
| 66 | +// Entity (SQL caching) — replaces in-memory IResponseCacheService |
| 67 | +services.AddFluentlyHttpClientEntity(connectionString); |
| 68 | +``` |
| 69 | + |
| 70 | +## Conventions |
| 71 | + |
| 72 | +- **C# coding style**: see [.github/instructions/csharp.instructions.md](.github/instructions/csharp.instructions.md) |
| 73 | +- **Test conventions**: see [.github/instructions/tests.instructions.md](.github/instructions/tests.instructions.md) |
| 74 | +- **Usage examples and API docs**: see [README.md](README.md) |
| 75 | +- **Planned work**: see [docs/TODO.md](docs/TODO.md) |
| 76 | + |
| 77 | +## Key Patterns |
| 78 | + |
| 79 | +- All builders return `this` — every method participates in a fluent chain |
| 80 | +- Extend request/client builder via extension methods on `FluentHttpRequestBuilder` / `FluentHttpClientBuilder` (see `*Extensions.cs` files) |
| 81 | +- Add custom headers at client level (default for all requests) or at request level (single request) |
| 82 | +- URI templates use `{param}` interpolation via `.WithInterpolationData(new { param = value })` |
| 83 | +- GraphQL: use `FluentHttpClientGqlExtensions` in `src/FluentlyHttpClient/GraphQL/` |
| 84 | +- File uploads: use `MultipartFormDataContentExtensions` in `src/FluentlyHttpClient/MultipartFormDataContentExtensions.cs` |
| 85 | + |
| 86 | +## Testing |
| 87 | + |
| 88 | +Tests use **xUnit + Shouldly + RichardSzalay.MockHttp**. |
| 89 | +`ServiceTestUtil.cs` and `FluentlyTestExtensions.cs` provide shared test helpers. |
| 90 | +Integration tests live in `test/Integration/` and reference the sample API project. |
| 91 | + |
| 92 | +## Entity Sub-Project |
| 93 | + |
| 94 | +`FluentlyHttpClient.Entity` adds persistent SQL-backed HTTP response caching. |
| 95 | +Requires running EF Core migrations: `dotnet ef migrations add <Name> --project src/FluentlyHttpClient.Entity`. |
| 96 | +Call `.Initialize()` on `FluentHttpClientDbContext` during app startup to apply migrations idempotently. |
0 commit comments