yamamoWorks

.NET技術を中心に気まぐれに更新していきます

ASP.NET Core Web APIでSnake Caseに対応する - Query編

前回はレスポンスBodyのJsonに「snake_case」を適応しました。 今回はアクションメソッドの引数の変数名はそのままに、クエリパラメータを「snake_case」でリクエストして動作させるのがゴールです。

おさらい

名称
Upper Camel Case (Pascal Case) FirstName
Lower Camel Case firstName
Snake Case first_name
Screaming Snake Case FIRST_NAME
Kebab Case first-name
Train Case First-Name

前提

こんなWeb APIがあったとします。

[ApiController]
public class UsersController : ControllerBase
{
    [HttpGet]
    public ActionResult<User[]> List([FromQuery]string firstName)
    {
        var users = new[] {
            new User { UserId = "001", FirstName = "Taro", LastName = "Yamada" },
            new User { UserId = "002", FirstName = "Hanako", LastName = "Yamada" }
        };
        return Ok(users.Where(u => firstName == null ? true : u.FirstName == firstName));
    }
}

この状態でのリクエストは「/api/users/?firstName=Taro」となります。

クエリパラメータに「snake_case」を適応する

当然、アクションメソッドの引数の変数名を「snake_case」に変えれば要件は満たされますが、全くもってスマートではありません。

// 変数名をsnake_caseに変える → 論外
[HttpGet]
public ActionResult<User[]> List([FromQuery]string first_name)

ASP.NET MVCにはクライアントから送信されたリクエストをアクションメソッドの引数に対応させるモデルバインドという機構があります。 標準ではQueryStringValueProviderが実装されており、クエリパラメータの値をアクションメソッドの引数として渡してくれます。 今回はこのQueryStringValueProviderを拡張して「snake_case」に対応させます。 [参考]:ASP.NET Core でのカスタム モデル バインド

QueryStringValueProviderを継承したSnakeCaseQueryStringValueProviderと、MVCフレームワークへの登録に必要なIValueProviderFactoryを実装したSnakeCaseQueryStringValueProviderFactoryを用意します。 あとはStartupクラスのConfigureServicesメソッド内でValueProviderFactoriesに登録すれば「/api/users/?first_name=Taro」のリクエストでアクションメソッドの引数「firstName」に"Taro"の値が渡るようになります。

services.AddMvc(
    options => options.ValueProviderFactories.Add(new SnakeCaseQueryStringValueProviderFactory()));

次回はSwaggerの対応です。