Major Changes to FHIR Client
Firely Updates
8 Min Read

Major Changes to the FHIR Client in Firely .NET SDK 2.0

Marten Smits

Subscribe to our newsletter

Subscribe

The complete rewrite of the FHIR Client was one of the bigger changes in the 2.0 release of the Firely .NET SDK. The original code of the FHIR Client was one of the first pieces of the SDK we’ve written, and it was time for an upgrade. Although the public interface looks very similar, the new FHIR Client comes with a couple of new, cool features.

Introducing HttpClient

When we first wrote the FHIR Client, Microsoft’s HttpWebRequest and HttpWebResponse mechanism was still the standard for writing REST Clients. In the meantime, Microsoft’s HttpClient has replaced the HttpWebResponse/Request pattern, which is much simpler to implement, has better async support, and still preserves the same amount of flexibility.  These were enough reasons for us to replace HttpWebResponse/Request with HttpClient. And so, we did.

As this change has been made in internal classes, most users will not notice a lot of differences or breaking code. However, things might be better for you now if you’ve had issues with using the FHIR Client async. The biggest improvement in my view is the HttpClient and thus that our new FHIR Client supports “chaining” of message handlers. This will make it a lot easier if you want to use authorization, logging, or any other custom handling of the rest client.

Note: If you are having trouble upgrading to this new client, you can still use the HttpWebResponse/Request pattern using the LegacyFhirClient.

Message Handlers

The previous version of the FHIR Client provided two event handlers that you could use to hook into the request/response cycle. With these handlers you could implement extra code to be executed right before a request is sent or directly after a response has been received. For example, when you want to send an authorization token with your request. Or perhaps you need another code to be executed each time the client sends a request. You could use the OnBeforeRequest event for this. The example below used to be the way to add an authorization header with a bearer token to the FHIR Client.

var client = new FhirClient("http://vonk.fire.ly/"); 
client.OnBeforeRequest += (object sender, BeforeRequestEventArgs e) =>
 {
         // Replace with a valid bearer token for the server
         e.RawRequest.Headers.Add("Authorization", "Bearer XXXXXXX");
 }; 

This wasn’t the most efficient way of doing it but it did the trick. However, if you want to add logging to this as well, you have to change the OnBeforeRequest to include the logging code which can feel a bit weird.

With HttpClient now as our new underlying best friend, OnBeforeRequest and OnAfterResponse are no longer available in the FhirClient. They are instead being replaced by an optional HttpMessageHandler in the constructor. The achieve the same result as above you can write your own message handler that handles authorization. Like so:

public class AuthorizationMessageHandler : HttpClientHandler
{
        public System.Net.Http.Headers.AuthenticationHeaderValue Authorization { get;set;}
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
                if (Authorization != null)
                        request.Headers.Authorization = Authorization;
                return await base.SendAsync(request, cancellationToken);
        }
}

Which can then be added to a FhirClient like this:

var handler = new AuthorizationMessageHandler();
var bearerToken = "AbCdEf123456" //example-token;
handler.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
var client = new FhirClient("http://vonk.fire.ly", FhirClientSettings.CreateDefault(), handler);
client.Read<Patient>("example");

This separates the authorization behavior from the client and makes it easier to reuse custom client behavior in different clients.

Chaining multiple message handlers

And now comes the cool part. You can also chain multiple HttpMessageHandlers to combine their functionality in a single FHIR Client. You can do this by using DelegatingHandler. A DelegatingHandler is a handler that is designed to be chained to another handler. This will effectively form a pipeline through which requests and responses will pass. Each handler has a chance to examine and/or modify the request before passing it to the next handler in the chain. It can also examine and/or modify the response it receives from the next handler. Typically, the last handler in the pipeline is the HttpClientHandler, which communicates directly with the network.

For example, next to a AuthorizationMessageHandler we created earlier, you might want to add a Logging Handler :

public class LoggingHandler : DelegatingHandler
{
        private readonly ILogger _logger;
 
        public LoggingHandler(ILogger logger)
        {
                _logger = logger;
        }
 
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
                _logger.Trace($"Request: {request}");
                try
                {
                        // base.SendAsync calls the inner handler
                        var response = await base.SendAsync(request, cancellationToken);
                        _logger.Trace($"Response: {response}");
                        return response;
                }
                catch (Exception ex)
                {
                        _logger.Error($"Failed to get response: {ex}");
                        throw;
                }
        }
}

Source: https://thomaslevesque.com/2016/12/08/fun-with-the-httpclient-pipeline/

If you want to combine this with the AuthorizationMessageHandler from the previous section, you can add that to the LoggingHandler as an InnerHeader, because the LoggingHandler implements DelegatingHandler. Like this:

var authHandler = new AuthorizationMessageHandler();
var loggingHandler = new LoggingHandler()
{
        InnerHandler = authHandler
};
var client = new FhirClient("http://vonk.fire.ly", FhirClientSettings.CreateDefault(), loggingHandler);

This puts the AuthorizationMessageHandler inside the LoggingHandler which is added to the client. This results in both handlers forming a pipeline through which requests and responses will pass.

Other changes

Next to changing the underlying mechanism of the client to HttpCient, we made some other changes. These are all changes we couldn’t do before because they would change the public interface. With a major version update, we took the opportunity to make some of these changes. See https://github.com/FirelyTeam/firely-net-sdk/wiki/Breaking-changes-in-2.0#changes-to-the-fhir-client for a list of changes in the FHIR Client and other breaking changes in the Firely .NET SDK.

We hope you value the improvements we made to the FHIR Client. If you encounter any problems or have suggestions for further improvements, please reach out to us on our GitHub page.

Thanks

I would like to thank everyone who has contributed to the improved FHIR client. Especially Devereux Henley: your pull request really made my life a lot easier.

Want to stay on top of Interoperability and Health IT? 

Subscribe to our newsletter for the latest news on FHIR. 

Post a comment

Your email address will not be published. Required fields are marked *