Wednesday, January 22, 2020

Flurl for HTTP Requests

If you're using HttpClient directly I'm here to tell you that there is a better way. Once I found Flurl I never looked back. I use it for all of my HTTP requests. However, before we dive into the advantages of Flurl let's take a look at what a lot of people aren't aware of concerning using HttpClient directly.

Why is this usage of HttpClient bad?


This is the typical usage pattern for how developers use HttpClient. Unfortunately, it's all wrong!!
using(var client = new HttpClient())
{
    //do something with http client
}
As noted in YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE using HttpClient in the manner shown above eats up socket connections and under heavy load will bring your site to its knees. In fact, Windows will hold the socket connection open servicing the above request for 240 seconds even though you correctly used the 'using' syntax. This will result in SocketException errors under heavy loads.

Flurl to the Rescue

Flurl solves the problem above and then some. I prefer the one-liner fluent HTTP request syntax that Flurl provides. I write Azure micro-services and consume REST API services both on a daily bases so I have put a lot of miles on Flurl, it just works. Using Flurl also lends itself to writing very readable code as well.

Let's look at an example.
// Grab our oAuth token, I'm being lazy here with the use of 'dynamic' type
dynamic accessToken = await "https://mywebsite.com/"
    .AppendPathSegment("oauth/token")
    .PostJsonAsync(new
    {
        client_id = "......",
        client_secret = "......",
        audience = "https://www.mywebsite.com/CoolRestAPI",
        username = "MyUser@CoolRestApi.com",
        password = "......",
        grant_type = "password"
    })
    .ReceiveJson();

// Grab the JWT token ...
string token = accessToken.access_token;

// Now make another call using our oAuth token to get a list of Widgets
WidgetCollection widgets = await "https://mywebsite.com/"
    .AppendPathSegment("/Widget")
    .WithOAuthBearerToken(token)
    .SetQueryParams(new
    {
        skip = 20,
        take = 50,
    })
    .AllowAnyHttpStatus()
    .GetJsonAsync();

Notice that the two HTTP requests made using Flurl above are one-line fluent calls. Also, and here's the kicker, think of the URL after the await keyword as the 'cache' indicator. That is, Flurl only used one HttpClient the above code and that would have been true had I made a 1,000 requests, as long as the URL is the same. So Flurl solves the HttpClient socket resource allocation issue and provides you with an amazingly simple way to make HttpClient calls. I use this approach in all of the micro-services I create. Flurl also works on Xamarin as well.

HttpClientFactory

Okay, so your company is insisting that you use HttpClientFactory via Dependency Injection because that's the Microsoft way. No worries, you can still use Flurl, all you need do is wrap the HttpClient with the FlurlClient and you can still use the Flurl fluent syntax.

[HttpGet]  
public static async Task ControllerMethod(HttpClient httpClient)
{
    // Flurl can use an existing HttpClient
    var flurlCient = new FlurlClient(httpClient);

    dynamic accessToken = await flurlCient.Request()
        .AppendPathSegment("oauth/token")
        .PostJsonAsync(new
        {
            client_id = "......",
            client_secret = "......",
            audience = "https://www.mywebsite.com/CoolRestAPI",
            username = "MyUser@CoolRestApi.com",
            password = "......",
            grant_type = "password"
        })
        .ReceiveJson(); 
}

In the above example the base url is already set to "https://mywebsite.com/" so all we need to do is append out path. I encourage you to give Flurl a try, just add the Flurl.Http NuGet package and you're off.


No comments:

Post a Comment