Extensibility

Since most of Flurl's functionality is provided through extension methods, it is very easy to extend using the same patterns that Flurl itself uses.

Extending the URL builder

Chainable URL builder methods generally come in sets of 3 overloads: one extending Flurl.Url, one extending System.Uri, and one extending String. All of these should return the modified Flurl.Url object:

public static Url DoMyThing(this Url url) {
    // do something interesting with url
    return url;
}

// keep these overloads DRY by constructing a Url and deferring to the above method
public static Url DoMyThing(this Uri uri) => new Url(uri).DoMyThing(); 
public static Url DoMyThing(this string url) => new Url(url).DoMyThing();

Extending Flurl.Http

Chainable Flurl.Http extension methods generally come in sets of 4, extending Flurl.Url, System.Uri, String, and IFlurlRequest. All should return the current IFlurlRequest to allow further chaining.

public static IFlurlRequest DoMyThing(this IFlurlRequest req) {
    // do something interesting with req.Settings, req.Headers, req.Url, etc.
    return req;
}

// keep these overloads DRY by constructing a Url and deferring to the above method
public static IFlurlRequest DoMyThing(this Url url) => new FlurlRequest(url).DoMyThing();
public static IFlurlRequest DoMyThing(this Uri uri) => new FlurlRequest(uri).DoMyThing();
public static IFlurlRequest DoMyThing(this string url) => new FlurlRequest(url).DoMyThing();

Now all of these work:

result = await "http://api.com"
    .DoMyThing() // string extension
    .GetAsync();

result = "http://api.com"
    .AppendPathSegment("endpoint")
    .DoMyThing() // Url extension
    .GetAsync();

result = "http://api.com"
    .AppendPathSegment("endpoint")
    .WithBasicAuth(u, p)
    .DoMyThing() // IFlurlRequest extension
    .GetAsync();

There are cases where you may want yet a fifth overload: an IFlurlClient extension. If your extension interacts only with Settings or Headers, recall that defaults for these exist at the client level, so for completeness it might make sense for your extension to support client-level defaults as well.


Spot an error or omission? Edit this page.