Setting Content for HttpClient Testing with JSON.NET and System.Text.Json

Setting up matches with HttpClient Interception library is one thing, but configuring the data it can return is another. In this post we take a look at the functionality around setting up the content payload to return.

Published on 15 June 2021

Introduction

In this series so far we have addressed the basic usage of the HttpClient Interception library by Just Eat and how throwing an exception on missing registrations can help with debugging. We've covered the basics of using bundles and also looked at using templating to work with the Just Eat HttpClient Interception library. However when we want to work with content, depending on how your content is processed, you might have got tripped up depending on what serialization library are using. Over the years the default go to JSON processing library in .NET has been JSON.NET by James Newton-King. It is the number one Nuget package on nuget.org and is now so feature rich while generally keeping backwards compatibility it's unreal. It's a real testament to the commitment James has for the library. Unsurprisingly JSON.NET is used with the HttpClient Interception library however you're not forced to use it.

Let's take a look at how this works.

Setting Your Content

WithContent is a really important method when building up your matches. WithContent doesn't setup up any of the properties that a match can execute on however it allows for specifying the return data from the match when found. The slight "pain point" when using WithContent directly is that it relies on working with byte[]. Working with a foundational data type allows for flexibility and extension but can be a little frustrating at time and can make you have to jump through some hoops to get it to work.

So if you don't have a handy byte[] kicking about what are the options?

Working with JSON

Quite a lot of modern APIs return JSON data. Working with JSON data is a well established practice so would make sense that there would be support for it out of the box? Well there is!

To allow for working with JSON but not have it tied into the builder directly there is a WithJsonContent extension method on HttpRequestInterceptionBuilder. This extension method allows for either a strongly typed instance, or an anonymous type, to be specified as the required return payload. This extension method delegates processing responsibility to the WithNewtonsoftJsonContent extension method as default. This uses the JSON.NET serialization functionality to convert the object instance provided into a string which then gets converted to the required byte[].

As expected this extension method allows serialization with an optional JsonSerializerSettings instance which can be passed into the method if called directly. I would recommend this is the preferred route to setting your JSON payload response if you have custom serializer settings.

var builder = new HttpRequestInterceptionBuilder()
    .ForHost("api.github.com")
    .ForPath("users/westdiscgolf")
    .ForHttps()
    .ForMethod(HttpMethod.Get)
    .WithJsonContent(
        new
        {
            login = "WestDiscGolf",
            name = "Adam Storr"
        }
    );

Above is an example of using the WithJsonContent extension method and passing in an anonymous type that shapes the return payload.

Working with System.Text.Json

But if you don't have models setup for JSON.NET and want to use System.Text.Json in your tests there is another extension method avaiilable which can be used for setting the content; this is WithSystemTextJsonContent.

As with the corresponding JSON.NET based extension method this too takes an object content to serialize into the response. It too is able to be called directly while passing in an optional JsonSerializerOptions instance so you have more control over how it will process the payload data. The System.Text.Json.JsonSerializer class has a method SerializeToUtf8Bytes on it which will serialize the object passed in to a byte[] without the intermediate step converting the object to string first.

var builder = new HttpRequestInterceptionBuilder()
    .ForHost("api.github.com")
    .ForPath("users/westdiscgolf")
    .ForHttps()
    .ForMethod(HttpMethod.Get)
    .WithSystemTextJsonContent(
        new
        {
            login = "WestDiscGolf",
            name = "Adam Storr"
        }
    );

Above is an example of using the WithSystemTextJsonContent extension method. This is exactly the same as the example above but explicitly uses System.Text.Json to perform the serialization.

Not all Data is JSON

JSON is quite a common payload but what happens when you want to return string values such as HTML?

There is also an extension method which will take content which is an arbitrary string value. The string value supplied to the method will be passed through Encoding.UTF8.GetBytes to retrieve the required byte[] which WithContent is expecting. This allows for testing HTML responses returned from matches as well as APIs which return arbitary strings which aren't JSON.

Conclusion

In this post we have reviewed the options out of the box for working with JSON payloads and how to setup the return content depending on whether you are using JSON.NET or System.Text.Json processing for your payloads. We have also touched on how to setup returning other string values, such as HTML, from the content.

If you’ve liked this post please check out my lightning talk about the basics of the library. In future posts I hope to continue to explore the library more so please subscribe to my rss feed (link below) and reach out to me on Twitter if you have any comments.