Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WithResponseHeaders and WithContentHeaders overloads #473

Closed
shaynevanasperen opened this issue Aug 23, 2022 · 7 comments · Fixed by #475
Closed

WithResponseHeaders and WithContentHeaders overloads #473

shaynevanasperen opened this issue Aug 23, 2022 · 7 comments · Fixed by #475
Labels
feature-request A request for new functionality
Milestone

Comments

@shaynevanasperen
Copy link

Is your feature request related to a problem? Please describe.

I have an extension method which allows me to register responses for intercepted requests such that each subsequent request that matches, returns a different response content. I do this by using a closure of a Counter object, which gets incremented using WithInterceptionCallback, as follows:

[EditorBrowsable(EditorBrowsableState.Never)]
static class HttpRequestInterceptionBuilderExtensions
{
    public static HttpRequestInterceptionBuilder WithJsonResponses<T>(
        this HttpRequestInterceptionBuilder builder,
        Func<int, T, CancellationToken, Task> callback,
        T[] content,
        JsonSerializerOptions? options = null)
    {
        var counter = new Counter(content.Length);
        T item = default!;

        return builder
            .WithInterceptionCallback(async (_, cancellationToken) =>
            {
                counter.Increment();
                item = content[counter.Value - 1];
                await callback(counter.Value, item, cancellationToken);
            })
            .WithMediaType("application/json")
            .WithContent(() =>
            {
                if (item is Exception exception)
                    throw exception;
                    
                return JsonSerializer.SerializeToUtf8Bytes(item, options);
            });
    }

    class Counter
    {
        readonly int _maxValue;

        public Counter(int maxValue) => _maxValue = maxValue;

        public int Value { get; private set; }

        public void Increment()
        {
            if (Value == _maxValue) return;

            Value++;
        }
    }
}

I would like to do the same for the response headers and content headers as well. This requires new overloads for WithResponseHeaders and WithContentHeaders, and some associated code changes.

Describe the solution you'd like

New overloads for WithResponseHeaders and WithContentHeaders, which allow passing a Func<IDictionary<string, ICollection<string>>>.

Describe alternatives you've considered

No alternatives exist.

Additional context

The reason for requiring different responses to the same request is that the API being "mocked" is one that returns data which changes over time. My test suite is set up so that I can verify this behaviour.

@shaynevanasperen shaynevanasperen added the feature-request A request for new functionality label Aug 23, 2022
@martincostello martincostello added this to the Future milestone Aug 24, 2022
martincostello added a commit to martincostello/httpclient-interception that referenced this issue Aug 24, 2022
Prototype implementation to support justeattakeaway#473.
@martincostello
Copy link
Member

I've pushed up a commit with a prototype/proof-of-concept of how this might work here: martincostello@fb9440d

Let me know if this would address your use case, and if it seems workable I can look at fleshing it out.

@shaynevanasperen
Copy link
Author

Thanks @martincostello!

That looks perfect for my use case, and it seems like a very elegant solution. Perhaps some async overload might be useful (like there already is for WithContent)? I don't currently need it to be async-friendly though, so it could be omitted if you don't think it's worth it.

@martincostello
Copy link
Member

Cool - glad it works for your use case.

I left out async to start with to get some fast feedback, however given the current internal design I don't know if it could be easily added or not. I'll consider it, but leave it out if it requires too much rework - it could always be added at a later date in a new major version if there's demand for it.

I'll look at circling back to this change and fleshing it out some time this week. Once I do that I'll push up a pull request, and you should be able to validate it via a preview NuGet package via the GitHub Actions CI to validate it before it goes into a release shipped to NuGet.org.

martincostello added a commit to martincostello/httpclient-interception that referenced this issue Aug 26, 2022
- Add support for dynamically matching and producing HTTP headers.
- Add missing null check.

Relates to justeattakeaway#473.
@martincostello martincostello modified the milestones: Future, v3.2.0 Aug 26, 2022
@martincostello
Copy link
Member

See #475.

You can download the packages from the build artifacts here (packages-*).

@shaynevanasperen
Copy link
Author

Thanks @martincostello.

I've tested it and it works great!

@martincostello
Copy link
Member

Thanks - I'll come back to finishing this off and prepping a release including the change next week when I'm back in the office.

martincostello added a commit to martincostello/httpclient-interception that referenced this issue Nov 15, 2022
Prototype implementation to support justeattakeaway#473.
martincostello added a commit to martincostello/httpclient-interception that referenced this issue Nov 15, 2022
- Add support for dynamically matching and producing HTTP headers.
- Add missing null check.

Relates to justeattakeaway#473.
@martincostello
Copy link
Member

This change is now available from NuGet.org.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A request for new functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants