MiniAPI（二十三）：Refit

本稿は、前稿のHttpClientに関連した内容です。前稿では、HttpClientを直接使用してリクエストを発行し、必要に応じてリクエスト情報を自分で埋める方法を取りました。では、Refitとは何でしょうか？APIを呼び出すことが、まるでオブジェクトのメソッドを呼び出すように簡単になるもので、httpリクエスト情報をインターフェースに設定し、Refitがこれらの情報を標準的なhttpリクエストに変換し、その後リクエストの結果を標準的なエンティティに変換して返してくれるものです。そのため、まるでオブジェクトのメソッドを使用しているような感覚になります。
以下は、get、post、put、deleteのシンプルな例です。
ここでは、データベースの役割を果たすメモリコレクションを定義しています。Userはエンティティクラスです。
```csharp
#region ストレージとエンティティクラス
/// <summary>
/// データベースのふり
/// </summary>
public static class DB
{
    /// <summary>
    /// データテーブルのふり
    /// </summary>
    public static List<User> users = new List<User>() {
    new User{ID=1,UserName="gsw",Name="张三",Password="ABCDE",CreateTime=DateTime.Now}
    };
}
/// <summary>
/// エンティティクラス
/// </summary>
public class User
{
    public int ID { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public string Name { get; set; }
    public DateTime CreateTime { get; set; }
    public DateTime ModifyTime { get; set; }
}
#endregion
```
以下のAPIは、メモリコレクションを操作してCRUD操作を行います。
```csharp
#region 呼ばれるAPI
app.MapGet("/users/{username}", (ILogger<Program> Logger, string userName) =>
{
    Logger.LogInformation("get userを呼ばれた");
    return DB.users.SingleOrDefault(s => s.UserName == userName);
});

app.MapPost("/user", (ILogger<Program> Logger, User user) =>
{
    Logger.LogInformation("add userを呼ばれた");
    user.ID = DB.users.Count + 1;
    DB.users.Add(user);
    return user;
});
app.MapPut("/user", (ILogger<Program> Logger, User user) =>
{
    Logger.LogInformation("modify userを呼ばれた");
    var oldUser = DB.users.SingleOrDefault(s => s.ID == user.ID);
    if (oldUser != null)
    {
        oldUser.UserName = user.UserName;
        oldUser.Password = user.Password;
        oldUser.Name = user.Name;
        oldUser.ModifyTime = DateTime.Now;
    }
    return oldUser;
});
app.MapDelete("/user/{id}", (ILogger<Program> Logger, int id) =>
{
    Logger.LogInformation("remove userを呼ばれた");
    var oldUser = DB.users.SingleOrDefault(s => s.ID == id);
    if (oldUser != null)
    {
        return DB.users.Remove(oldUser);
    }
    else
    {
        return false;
    }
});
#endregion
```
これはRefitの使用方法で、まずRefit.HttpClientFactory NuGetパッケージを導入し、RefitClientサービスをサービスコンテナーに注入します。ここでIUserAPIを指定し、BaseAddressを設定します。IUserAPIはAPIインターフェースの型を定義しており、各メソッド上の属性が下流APIへのリクエスト情報を決定します。次に使用する三つのメソッドを呼び出します。ここでの引数は固定されているので、シンプルな呼び出しのみをデモンストレーションします。
```csharp
using Refit;
var builder = WebApplication.CreateBuilder(args);

// RefitClientの設定
builder.Services
    .AddRefitClient<IUserAPI>()
    .ConfigureHttpClient(httpclient => httpclient.BaseAddress = new Uri("http://localhost:5026"));

var app = builder.Build();

#region 呼び出し側
app.MapGet("/user", async (ILogger<Program> Logger, IUserAPI userAPI) => { 
    Logger.LogInformation("呼び出し側 get user"); 
    var user = await userAPI.GetUser("gsw"); 
    user.Name += "丰"; 
    return user; });

app.MapPost("/user", async (ILogger<Program> Logger, IUserAPI userAPI) => {
    Logger.LogInformation("呼び出し側 add user"); 
    var user = new User { UserName = "ls", Name = "李四", Password = "EDCBA", CreateTime = DateTime.Now }; 
    var newUser = await userAPI.AddUser(user); 
    return newUser; });

app.MapPut("/user", async (ILogger<Program> Logger, IUserAPI userAPI) => {
    Logger.LogInformation("呼び出し側 modify user"); 
    var user = new User { ID = 2, UserName = "ls", Name = "李四收", Password = "AAAAA" }; 
    return await userAPI.ModifyUser(user); });

app.MapDelete("/user", async (ILogger<Program> Logger, IUserAPI userAPI) => {
    Logger.LogInformation("呼び出し側 remove user"); 
    return await userAPI.RemoveUser(2); });
#endregion
app.Run();

/// <summary>
/// Refitインターフェースの定義
/// </summary>
public interface IUserAPI
{
    [Get("/users/{username}")]
    Task<User> GetUser(string userName);

    [Post("/user")]
    Task<User> AddUser(User user);

    [Put("/user")]
    Task<User> ModifyUser(User user);

    [Delete("/user/{id}")]
    Task<bool> RemoveUser(int id);
}
```
HttpClientによるAPIの呼び出しは、非常に広範な知識です。多くのAPIはこれほど単純ではありませんが、Refitもいくつかの複雑な設定インターフェースを提供しています。詳細はhttps://github.com/reactiveui/refit を参照してください。シナリオは多岐にわたるため、文書を参照して自分に合った設定を見つけてください。しかし、Refitは万能ではありません。一般的なシナリオに対応するだけで、あまりにも完璧な解決策を求める必要はありません。結局のところ、それはあくまで一つのライブラリに過ぎません。

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247484981&idx=1&sn=ff2764001f66285c4a55f295ea8f7d4d&chksm=9f00591fa877d0090deb59976f223b57ba071703837dd5fa1a575c50ca2d4607a8b59a0d5e19&token=347102560&lang=zh_CN#rd