Sure, you could write all those Blazor HTTP calls yourself...
July 15, 2021 · 4 minute read · Tags: blazor
If you’re building a Blazor WASM application you’re almost certainly going to wind up making calls to an API.
The typical way to do this is to use HttpClient:
@using System.Net.Http
@using System.Net.Http.Json
@using System.Threading.Tasks
@inject HttpClient Http
@code {
private Customer[] customers;
protected override async Task OnInitializedAsync() {
customers = await Http.GetFromJsonAsync<Customer[]>("api/Customer");
}
}
This works well, but it does carry a few limitations.
Firstly, your Blazor components are suddenly very tied to that "api/Customer"
magic string for the URL of the API endpoint.
If you find yourself making similar calls from more than one component you’re probably going to end up referencing the same endpoint multiple times in different places, meaning any changes to the URL and you’ll be updating multiple components.
Secondly, the API isn’t very discoverable for you or any other developer working on the project.
To consume the API you have to know:
- The URL of the endpoint
- The type of the response
- Potentially the shape (or type) of any data needed for the request
I recently had the chance to work on a new Blazor project and found myself facing these problems, so I had a look for an alternative approach.
Refit can take care of the boilerplate code for you
With Refit you can create a strongly typed interface for your API which moves all this knowledge about URLs, request and response types into one place.
Assuming you already have an API up and running as per our example earlier, you can create a Refit API client like this:
using Refit;
public interface CustomerApi {
[Get("/Customer")]
Task<Customer[]> List();
}
You’ll also need a little bit of configuration in your Blazor’s program.cs file.
private static async Task Run(WebAssemblyHostBuilder builder, string[] args)
{
var apiUrl = "http://localhost:5001/api";
builder.Services.AddRefitClient<CustomerApi>()
.ConfigureHttpClient(c => { c.BaseAddress = new Uri(apiUrl); });
// other code...
}
Now you can happily go ahead and invoke the Api from your Blazor components.
@inject CustomerApi CustomerApi
@code {
private Customer[] customers;
protected override async Task OnInitializedAsync() {
customers = await CustomerApi.List();
}
}
This takes a lot of the guesswork out of consuming your API.
Once this Refit API is in place you can make use of it to call your API without constantly trying to remember (and/or find out) which URL, request or response type to use.
Naturally it works for HTTP POST requests as well:
using Refit;
public interface CustomerApi {
[Get("/Customer")]
Task<Customer[]> List();
[Post("/Customer")]
Task Create(Customer customer);
}
Automatically attaching JWTs
Blazor can automatically attach JWT access tokens to your outgoing requests if you configure your Http Client to use AuthorizationMessageHandler
.
Under the hood this makes sure the authorization
request header includes your Bearer access token (if you’re logged in to the application).
Here’s how I was able to get that working with Refit.
private static async Task Run(WebAssemblyHostBuilder builder, string[] args)
{
var apiUrl = "http://localhost:5001/api";
builder.Services.AddRefitClient<CustomerApi>()
.ConfigureHttpClient(c => { c.BaseAddress = new Uri(apiUrl); })
.AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(new[] {apiUrl}));
// other code...
}
The key is to make sure you configure the handler with the base address for your API (the call to ConfigureHandler
).
AuthorizationMessageHandler
will only attach tokens when you make requests to a URI which starts with that Base URL.
In summary
You can cut down on some boilerplate code, reduce the number of magic strings and improve the discoverability of your API by using the handy Refit library.
Find out more at the Refit Github repository.