Refit: Question: generic response processor

Created on 27 Jul 2018  路  4Comments  路  Source: reactiveui/refit

I'm using dotnet core HttpClientFactory and Refit together (and loving it!). This is not a dotnet core related question but here is what I'm trying to do.

Imagine the following API - except it has many different methods and return types other than string and int as per the example.

public interface ISomeApi
{
    [Get("/string")]
    Task<string> GetString();

    [Get("/int")]
    Task<int> GetInt();
}

public class ErrorResponse
{
    public string SomeErrorProperty { get; set; }
}

public class Test
{
    private readonly ISomeApi _someApi;

    public Test(ISomeApi someApi)
    {
        _someApi = someApi;
    }

    public async Task<SomeApiResponse<string>> TestString()
    {
        var result = new SomeApiResponse<string>();

        try
        {
            var stringValue = await _someApi.GetString();
            result.StatusCode = 200;
            result.Data = stringValue;
        }
        catch (ApiException e)
        {
            var error = e.GetContentAs<ErrorResponse>();
            result.StatusCode = (int) e.StatusCode;
            result.Error = error;
        }    

        return result;
    }

    public async Task<SomeApiResponse<int>> TestInt()
    {
        var result = new SomeApiResponse<int>();

        try
        {
            var intValue = await _someApi.GetInt();
            result.StatusCode = 200;
            result.Data = intValue;
        }
        catch (ApiException e)
        {
            var error = e.GetContentAs<ErrorResponse>();
            result.StatusCode = (int) e.StatusCode;
            result.Error = error;
        }

        return result;
    }
}

public class SomeApiResponse<T>
{
    public int StatusCode { get; set; }
    public T Data { get; set; }
    public ErrorResponse Error { get; set; }
}

I want to avoid having to write the catch (ApiException e) everywhere and just change the signature of my APIs to be something like this. Is it possible to do by somehow intercepting the HttpResponseMessage in one place? Like a custom DelegatingHandler but it executes fairly late in the process.

public interface ISomeApi
{
    [Get("/string")]
    Task<SomeApiResponse<string>> GetString();

    [Get("/int")]
    Task<SomeApiResponse<int>> GetInt();
}
outdated

Most helpful comment

It makes it better but I'm looking for something like ApiResponse<TSuccess, TFailure>. Not suggesting that the framework should support it but I was thinking if there was a way to write a generic response processor for a given API where I can do this on my own so I don't write too many bolierplate catch (ApiException e) everywhere.

All 4 comments

Does ApiResponse<T> do what you want?

[Get("/int")]
Task<ApiResponse<int>> GetInt();

var response = await api.GetInt();
if(response.IsSuccessStatusCode) 
{
    // happy path
} 
else 
{
    // handle error
}

It doesn't give you access to the raw response if there's an error, but it won't throw if there is one.

It makes it better but I'm looking for something like ApiResponse<TSuccess, TFailure>. Not suggesting that the framework should support it but I was thinking if there was a way to write a generic response processor for a given API where I can do this on my own so I don't write too many bolierplate catch (ApiException e) everywhere.

@hiraldesai @bennor solution with ApiResponse won't work. Please see #537

Fix by @onovotny mentioned in #537 kind of gives me what I was looking for.

Was this page helpful?
0 / 5 - 0 ratings