66[ ![ CI] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml/badge.svg )] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml )
77[ ![ NuGet version] ( https://badge.fury.io/nu/fluentlyhttpclient.svg )] ( https://badge.fury.io/nu/fluentlyhttpclient )
88
9- Http Client for .NET Standard with fluent APIs which are intuitive, easy to use and also highly extensible.
9+ Http Client for .NET with fluent APIs which are intuitive, easy to use and also highly extensible.
1010
1111** Quick links**
1212
@@ -35,6 +35,7 @@ Http Client for .NET Standard with fluent APIs which are intuitive, easy to use
3535| 2.x | .NET Standard 2 | |
3636| 3.x | .NET Standard 2 | [ ![ CI] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml/badge.svg?branch=3.x )] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml ) |
3737| 4.x | net8 | [ ![ CI] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml/badge.svg?branch=v4 )] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml ) |
38+ | 5.x | net10 | [ ![ CI] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml/badge.svg?branch=v5 )] ( https://github.com/sketch7/FluentlyHttpClient/actions/workflows/ci.yml ) |
3839
3940### NuGet
4041```
@@ -69,7 +70,7 @@ PM> Install-Package FluentlyHttpClient
6970 - [ Usage] ( #usage-1 )
7071 - [ Query params] ( #query-params )
7172 - [ Interpolate Url] ( #interpolate-url )
72- - [ ReturnAsReponse , ReturnAsResponse` <T> ` and Return` <T> ` ] ( #returnasreponse -returnasresponset-and-returnt )
73+ - [ ReturnAsResponse , ReturnAsResponse` <T> ` and Return` <T> ` ] ( #returnasresponse -returnasresponset-and-returnt )
7374 - [ GraphQL] ( #graphql )
7475 - [ Middleware] ( #middleware )
7576 - [ Middleware options] ( #middleware-options )
@@ -84,35 +85,28 @@ PM> Install-Package FluentlyHttpClient
8485 - [ Simple Single file HttpClient] ( #simple-single-file-httpclient )
8586 - [ Testing/Mocking] ( #testingmocking )
8687 - [ Test example with RichardSzalay.MockHttp] ( #test-example-with-richardszalaymockhttp )
87- - [ Contributing] ( #contributing )
88- - [ Setup Machine for Development] ( #setup-machine-for-development )
89- - [ Commands] ( #commands )
9088
9189## Usage
9290
9391### Configure
9492Add services via ` .AddFluentlyHttpClient() ` .
9593
9694``` cs
97- // using Startup.cs (can be elsewhere)
98- public void ConfigureServices (IServiceCollection services )
99- {
100- services .AddFluentlyHttpClient ();
101- }
95+ // Program.cs
96+ var builder = WebApplication .CreateBuilder (args );
97+ builder .Services .AddFluentlyHttpClient ();
98+ var app = builder .Build ();
10299```
103100
104- Configure an Http client using the Http Factory (you need at least one).
101+ Configure an HTTP client using the HTTP client factory (you need at least one).
105102``` cs
106- // using Startup.cs (can be elsewhere)
107- public void Configure (IApplicationBuilder app , IFluentHttpClientFactory fluentHttpClientFactory )
108- {
109- fluentHttpClientFactory .CreateBuilder (identifier : " platform" ) // keep a note of the identifier, its needed later
110- .WithBaseUrl (" http://sketch7.com" ) // required
111- .WithHeader (" user-agent" , " slabs-testify" )
112- .WithTimeout (5 )
113- .UseMiddleware <LoggerHttpMiddleware >()
114- .Register (); // register client builder to factory
115- }
103+ var fluentHttpClientFactory = app .Services .GetRequiredService <IFluentHttpClientFactory >();
104+ fluentHttpClientFactory .CreateBuilder (identifier : " platform" ) // keep a note of the identifier, it's needed later
105+ .WithBaseUrl (" https://sketch7.com" ) // required
106+ .WithHeader (" user-agent" , " my-app" )
107+ .WithTimeout (5 )
108+ .UseMiddleware <LoggerHttpMiddleware >()
109+ .Register (); // register client builder to factory
116110```
117111
118112### Basic usage
@@ -124,11 +118,11 @@ Simple API (non-fluent) is good for simple requests as it has a clean, minimal A
124118// inject factory and get client
125119var httpClient = fluentHttpClientFactory .Get (identifier : " platform" );
126120
127- // HTTP GET + deserialize result (non-fleunt API)
128- Hero hero = await httpClient .Get <Hero >(" /api/heroes/azmodan" );
121+ // HTTP GET + deserialize result (non-fluent API)
122+ Hero ? hero = await httpClient .Get <Hero >(" /api/heroes/azmodan" );
129123
130- // HTTP POST + deserialize result (non-fleunt API)
131- Hero hero = await httpClient .Post <Hero >(" /api/heroes/azmodan" , new
124+ // HTTP POST + deserialize result (non-fluent API)
125+ Hero ? hero = await httpClient .Post <Hero >(" /api/heroes/azmodan" , new
132126 {
133127 Title = " Lord of Sin"
134128 });
@@ -147,7 +141,7 @@ FluentHttpResponse<Hero> response =
147141 .ReturnAsResponse <Hero >(); // return with response
148142
149143// HTTP POST + return response and deserialize result (fluent API)
150- Hero hero = await httpClient .CreateRequest (" /api/heroes/azmodan" )
144+ Hero ? hero = await httpClient .CreateRequest (" /api/heroes/azmodan" )
151145 .AsPost ()
152146 .WithBody (new
153147 {
@@ -163,11 +157,11 @@ Http client builder is used to configure http clients in a fluent way.
163157
164158``` cs
165159var clientBuilder = fluentHttpClientFactory .CreateBuilder (identifier : " platform" )
166- .WithBaseUrl (" http ://sketch7.com" );
160+ .WithBaseUrl (" https ://sketch7.com" );
167161fluentHttpClientFactory .Add (clientBuilder );
168162
169163// or similarly via the builder itself.
170- clientBuilder .Register ().
164+ clientBuilder .Register ();
171165```
172166
173167#### Register multiple + share
@@ -237,7 +231,8 @@ httpClientBuilder.ConfigureFormatters(opts =>
237231 opts .Formatters .Add (new CustomFormatter ());
238232 });
239233
240- httpClientBuilder .WithVersion (HttpVersion .Version30 ) // specify to use http3 (defaults: http2)
234+ // http version - configure per-request via request builder defaults
235+ httpClientBuilder .WithRequestBuilderDefaults (builder => builder .WithVersion (HttpVersion .Version30 )); // specify http3 per-request (default: http2)
241236```
242237
243238#### Re-using Http Client from Factory
@@ -259,7 +254,7 @@ Request builder is used to build http requests in a fluent way.
259254#### Usage
260255
261256``` cs
262- LoginResponse loginResponse =
257+ LoginResponse ? loginResponse =
263258 await fluentHttpClient .CreateRequest (" /api/auth/login" )
264259 .AsPost () // set as HTTP Post
265260 .WithBody (new
@@ -292,7 +287,7 @@ requestBuilder.WithUri("{Language}/heroes/{Hero}", new
292287 }); // => /en/heroes/azmodan
293288```
294289
295- #### ReturnAsReponse , ReturnAsResponse` <T> ` and Return` <T> `
290+ #### ReturnAsResponse , ReturnAsResponse` <T> ` and Return` <T> `
296291
297292``` cs
298293// send and returns HTTP response
@@ -301,8 +296,8 @@ FluentHttpResponse response = requestBuilder.ReturnAsResponse();
301296// send and returns HTTP response + deserialize and return result via `.Data`
302297FluentHttpResponse < Hero > response = requestBuilder .ReturnAsResponse <Hero >();
303298
304- // send and returns derserialized result directly
305- Hero hero = requestBuilder .Return <Hero >();
299+ // send and returns deserialized result directly
300+ Hero ? hero = requestBuilder .Return <Hero >();
306301```
307302
308303
@@ -317,7 +312,7 @@ httpClientBuilder.WithRequestBuilderDefaults(requestBuilder => requestBuilder.Wi
317312FluentHttpResponse < Hero > response =
318313 await fluentHttpClient .CreateGqlRequest (" { hero {name, title } }" )
319314 .ReturnAsGqlResponse <Hero >();
320- // => response.Data.Title
315+ // => response.Data? .Title
321316```
322317
323318
@@ -334,9 +329,9 @@ These are provided out of the box:
334329| Timer | Determine how long (timespan) requests takes. |
335330| Logger | Log request/response. |
336331
337- Two important points to keep in mind:
332+ Three important points to keep in mind:
338333 - The first argument within constructor has to be ` FluentHttpMiddlewareDelegate ` which is generally called ` next ` .
339- - The second argument within constructor has to be ` FluentHttpMiddlewareClientContext ` which is generally called ` context ` ,
334+ - The second argument within constructor has to be ` FluentHttpMiddlewareClientContext ` which is generally called ` context ` .
340335 - During ` Invoke ` the ` await _next(context); ` must be invoked and return the response, in order to continue the flow.
341336
342337 The following is the timer middleware implementation * (bit simplified)* .
@@ -388,7 +383,7 @@ namespace FluentlyHttpClient
388383 // FluentHttpClientBuilder extension methods - add
389384 public static class FluentlyHttpMiddlwareExtensions
390385 {
391- public static FluentHttpClientBuilder UseTimer (this FluentHttpClientBuilder builder , TimerHttpMiddlewareOptions options = null )
386+ public static FluentHttpClientBuilder UseTimer (this FluentHttpClientBuilder builder , TimerHttpMiddlewareOptions ? options = null )
392387 => builder .UseMiddleware <TimerHttpMiddleware >(options ?? new TimerHttpMiddlewareOptions ());
393388 }
394389}
@@ -398,7 +393,7 @@ TimeSpan timeTaken = response.GetTimeTaken();
398393```
399394
400395#### Middleware options
401- Options to middleware can be passed via an argument. Note it has to be the second argument within the constructor.
396+ Options to middleware can be passed via an argument. Note it has to be the third argument within the constructor (after ` next ` and ` context ` ) .
402397
403398``` cs
404399public TimerHttpMiddleware (
@@ -482,13 +477,14 @@ public static class FluentHttpHeaderBuilderExtensions
482477 builder .WithHeader (HeaderTypes .Authorization , $" {AuthSchemeTypes .Bearer } {token }" );
483478 return (T )builder ;
484479 }
480+ }
485481```
486482#### Extending Request/Response items
487483In order to extend ` Items ` for both ` FluentHttpRequest ` and ` FluentHttpResponse ` , its best to extend ` IFluentHttpMessageState ` .
488484This way it will be available for both. See example below.
489485
490486``` cs
491- public static IDictionary<string, string> GetErrorCodeMappings(this IFluentHttpMessageState message )
487+ public static IDictionary < string , string > ? GetErrorCodeMappings (this IFluentHttpMessageState message )
492488{
493489 if (message .Items .TryGetValue (ErrorCodeMappingKey , out var value ))
494490 return (IDictionary < string , string > )value ;
@@ -526,7 +522,7 @@ public class SelfInfoHttpClient
526522 )
527523 {
528524 _httpClient = httpClientFactory .CreateBuilder (" localhost" )
529- .WithBaseUrl ($ " http://localhost:5500} " )
525+ .WithBaseUrl (" http://localhost:5500" )
530526 .Build ();
531527 }
532528
@@ -545,14 +541,14 @@ However, we've been using [RichardSzalay.MockHttp](https://github.com/richardsza
545541
546542``` cs
547543[Fact ]
548- public async void ShouldReturnContent ()
544+ public async Task ShouldReturnContent ()
549545{
550546 // build services
551547 var servicesProvider = new ServiceCollection ()
552548 .AddFluentlyHttpClient ()
553549 .AddLogging ()
554550 .BuildServiceProvider ();
555- var fluentHttpClientFactory = servicesProvider .GetService <IFluentHttpClientFactory >();
551+ var fluentHttpClientFactory = servicesProvider .GetRequiredService <IFluentHttpClientFactory >();
556552
557553 // define mocks
558554 var mockHttp = new MockHttpMessageHandler ();
@@ -561,7 +557,7 @@ public async void ShouldReturnContent()
561557
562558 var httpClient = fluentHttpClientFactory .CreateBuilder (" platform" )
563559 .WithBaseUrl (" https://sketch7.com" )
564- .AddMiddleware <TimerHttpMiddleware >()
560+ .UseMiddleware <TimerHttpMiddleware >()
565561 .WithMessageHandler (mockHttp ) // set message handler to mock
566562 .Build ();
567563
@@ -573,28 +569,3 @@ public async void ShouldReturnContent()
573569 Assert .NotEqual (TimeSpan .Zero , response .GetTimeTaken ());
574570}
575571```
576-
577- ## Contributing
578-
579- ### Setup Machine for Development
580- Install/setup the following:
581-
582- - NodeJS v8+
583- - Visual Studio Code or similar code editor
584- - Git + SourceTree, SmartGit or similar (optional)
585-
586- ### Commands
587-
588- ``` bash
589- # run tests
590- npm test
591-
592- # bump version
593- npm version minor --no-git-tag # major | minor | patch | prerelease
594-
595- # nuget pack (only)
596- npm run pack
597-
598- # nuget publish dev (pack + publish + clean)
599- npm run publish:dev
600- ```
0 commit comments