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

feature: Get Request Url without making the Request #1201

Open
j-bbr opened this issue Jul 21, 2021 · 0 comments
Open

feature: Get Request Url without making the Request #1201

j-bbr opened this issue Jul 21, 2021 · 0 comments

Comments

@j-bbr
Copy link

j-bbr commented Jul 21, 2021

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

Sometimes when using an API we just want to build the request URL and make the request later or have it handled by another component. For example when requesting an Image we might give the Url to a component that makes the actual request only when the container becomes visible. Getting the Url from the client is possible only by looking at the ApiResponse after making the request

Describe the solution you'd like

I'd like an easy way to get to the build Uri without making a request.

Describe alternatives you've considered

Using a delegating handler we can get the Url and short circuit the request. Downside is that we have to provide mock content for client methods that parse the response or catch the exception as well as the overhead of creating a separate client.

Sample Implementation:

 public static class RefitExtensions
    {
        public static UriInterceptor<TClient> CreateUriInterceptor<TClient>(Uri baseUri) where TClient : class
        {
            var mockHandler = new UrlKeepingHandler();
            var serviceProvider = new ServiceCollection()
                .AddRefitClient<TClient>()
                .AddHttpMessageHandler(_ => mockHandler)
                .ConfigureHttpClient(c => c.BaseAddress = baseUri)
                .Services
                .BuildServiceProvider();
               
            
            return new UriInterceptor<TClient>(mockHandler,  
                serviceProvider.GetRequiredService<TClient>(), serviceProvider);
        }
    }

    public class UriInterceptor<TClient> : IDisposable where TClient : class 
    {
        private readonly UrlKeepingHandler _mockHandler;
        private readonly TClient _client;
        private readonly IDisposable _connectedDisposable;

        public UriInterceptor(UrlKeepingHandler mockHandler, TClient client, IDisposable connectedDisposable)
        {
            _mockHandler = mockHandler;
            _client = client;
            _connectedDisposable = connectedDisposable;
        }

        public async Task<Uri> GetRequestUri(Func<TClient, Task> requestAction, HttpContent dummyContent = null)
        {
            if (dummyContent != null)
                _mockHandler.MockContent = dummyContent;
            try
            {
                await requestAction(_client);
            }
            catch
            {
                // ignored
            }

            return _mockHandler.LastRequestUri;
        }

        public void Dispose()
        {
            _mockHandler?.Dispose();
            _connectedDisposable?.Dispose();
        }
    }
    
    public class UrlKeepingHandler : DelegatingHandler
    {
        public Uri LastRequestUri { get; private set; }

        public HttpContent MockContent { get; set; }


        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            LastRequestUri = request.RequestUri;
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            if (MockContent != null)
                response.Content = MockContent;
            return Task.FromResult(response);
        }
    }

Describe suggestions on how to achieve the feature

The solution could be similar to above where a mock refit client implementation is passed in a lambda and the Uri resulting from a Method execution inside the lambda is returned. Ideally this solution avoids the overhead of the alternative above, doesn't involve HTTP client and trying to parse the response.

Additional context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant