APIサービスを作成し、WPFアプリケーションからの情報を利用したいと思います。
これまでに、APIエンドポイントの呼び出しに使用されるApiHelper
を初期化して提供するクラスHttpClient
と、取得するメソッドを公開するクラスMemberService
を作成しましたAPIから取得するデータ。
public class ApiHelper : IApiHelper
{
private readonly IConfiguration _config;
public HttpClient ApiClient { get; private set; }
public ApiHelper(IConfiguration config)
{
_config = config;
InitializeClient();
}
private void InitializeClient()
{
string apiBase = _config["api"];
ApiClient = new HttpClient
{
BaseAddress = new Uri(apiBase)
};
ApiClient.DefaultRequestHeaders.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
これはサービスです:
public class MemberService : IMemberService
{
private readonly IApiHelper _apiHelper;
public MemberService(IApiHelper apiHelper)
{
_apiHelper = apiHelper;
}
public async Task<List<Member>> GetAllMembersAsync()
{
using (HttpResponseMessage response = await _apiHelper.ApiClient.GetAsync("/api/Members"))
{
// If the response has a successful code...
if (response.IsSuccessStatusCode)
{
// Read the response
var result = await response.Content.ReadAsAsync<List<MemberResponse>>();
var output = AutoMapping.Mapper.Map<List<Member>>(result);
return output;
}
else
// If the response is not successful
{
// Error handling here
}
}
return null;
}
私の質問は、try catch
ブロックで処理できるHttpRequestException
などのエラーの処理ではなく、2xxの範囲にないステータスコードで応答を処理する方法です。
特に、APIのエンドポイントはトークンで保護されているため、ユーザーはリクエストを行う前に認証を行う必要があり、トークンの有効期限が切れた後は、トークンを更新する必要があります。
私がしたいことは、応答が401 - Unauthorized
のステータスの場合、例外をスローしたり、エラーメッセージでオブジェクトを返したりするのではなく、メソッドがトークンを更新しようとすることです(呼び出し別のサービスの適切なメソッド)。期限切れになる可能性があり、呼び出しが再び失敗した場合にのみ、例外をスローします。すべてのAPI呼び出しでこの動作が必要です。
API呼び出しを扱うのは初めてなので、これは私がやろうと思っていたことですが、その方法についていくつかのヒントを教えてください。これを達成するための最良のアプローチは何ですか?または、API呼び出しを行い、その応答を管理する別の方法を提案しますか?
私がやりたいのは、応答のステータスが401-Unauthorizedの場合、例外をスローしたり、エラーメッセージでオブジェクトを返したりするのではなく、メソッドがトークンを更新しようとする必要があります(別のサービスで適切なメソッドを呼び出す)。期限切れになる可能性があり、呼び出しが再び失敗した場合にのみ、例外をスローします。すべてのAPI呼び出しでこの動作が必要です。
それは素晴らしいアイデアのように思えます。
それを行うためのヘルパーメソッドから始めましょう。
_public class ApiHelper : IApiHelper
{
...
public async HttpContent 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
...
}
}
_
次に、カプセル化を使用して、ビジネスロジックが誤って発生しないようにしますbypassヘルパーメソッド:ApiClient
を非公開にし、必要に応じて新しい低レベルヘルパーメソッドを追加します。
要約トランスポートメカニズムへの最初のステップが完了しました。これにより、コードがトランスポート層の問題に対処するのではなく、問題ドメインの問題を解決することに集中できるようになるため、ビジネスロジックの可読性が向上します。常に同じデシリアライゼーションロジックを使用する場合は、それをApiHelperにも追加することをお勧めします(例:public async TResult GetAuthenticatedAsync<TResult, TResultMessage>(string requestUri)
)。
また、単体テストも簡単になります。認証の問題は、ApiHelper
をテストするのではなく、MemberService
をテストすることでテストする必要があります。