What I'd like to do is when the response has a status of 401 - Unauthorized, instead of throwing an exception or returning an object with an error message, the method should try to refresh the token (calling the appropriate method in another service) because it could be expired and just if the call fails again, throw the exception. I'd like to have this behavior for all the API calls.
That sounds like a great idea.
Let's start with a helper method to do exactly that:
public class ApiHelper : IApiHelper
{
...
public async HttpContent GetAuthenticatedAsync<T>GetAuthenticatedAsync(string requestUri)
{
var response = await ApiClient.GetAsync(requestUri);
// Pseudo code:
//
// if (200): return response.Content
// if (401):
// refresh token
// try GetAsync again
// if (200): return response
// else: throw meaningful exception - something is wrong with our credentials
// else: throw meaningful exception - unexpected return value
...
}
}
Then I'd use encapsulation to ensure that your business logic can't accidentally bypass your helper method: Make ApiClient private and add new low-level helper methods as needed.
You have now taken the first step to abstract away the transport mechanism. This improves readability of your business logic, since the code there can now concentrate on solving problems in your problem domain, rather than dealing with issues on the transport layer. If you always use the same deserialization logic, it might make sense to put that into ApiHelper as well (e.g. some public async TResult GetAuthenticatedAsync<TResult, TResultMessage>(string requestUri)).
It will also make unit testing easier: Authentication issues should be tested by testing ApiHelper, not by testing MemberService.