💻

可変キーのJSONをSwaggerとC#でモデリングする方法

2023/10/10に公開

可変キーのJSONとは

ここではJSONの構造としてキーが動的に変わることを指しています。
例えば、キー自体が商品IDとなるオブジェクトで、その属性として、商品名や価格などが含まれる場合です。

  "inheritsOrdetItems": {
    "{!商品ID}": {
      "itemName": "りんご",
      "itemPrice": 250
    },
    "{!商品ID}": {
      "itemName": "ばなな",
      "itemPrice": 150
    },
    "{!商品ID}": {
      "itemName": "みかん",
      "itemPrice": 300
    }
  }

Swaggerにはどう定義するの?

Swaggerに可変キーを持つオブジェクトを定義する場合、additionalProperties を使用します。

Swagger.yaml
inheritsOrdetItems:
  type: object
  additionalProperties:
    type: object
    description: 商品ID ※このキーは可変
    properties:
      itemName:
        type: string
        description: 商品名
        example: りんご
      itemPrice:
        type: integer
        description: 価格
        example: 250
        format: int32

上記の定義により、inheritsOrdetItems はどんなキー名も受け入れることができ、そのキーの値は指定された形式のオブジェクトとしています。
また、Swagger UI上では additionalProp1~3 と表記されるため、Swagger.yaml の description 定義にキーが可変である旨記載しておくと良いでしょう。

{
  "inheritsOrdetItems": {
    "additionalProp1": {
      "itemName": "りんご",
      "itemPrice": 250
    },
    "additionalProp2": {
      "itemName": "りんご",
      "itemPrice": 250
    },
    "additionalProp3": {
      "itemName": "りんご",
      "itemPrice": 250
    }
  }
}

C#で値を受け取るモデルクラスの構造はどうなるの?

可変キーを持つオブジェクトを .NET で受け取るには Dictionary を使ってモデルを定義します。

csharp
using System.Collections.Generic;

namespace AdditionalPropertiesJson
{
    public class InheritsOrdetItem
    {
        public Dictionary<string, ItemDetail> InheritsOrdetItems { get; set; }
    }

    public class ItemDetail
    {
        public string ItemName { get; set; }
        public int ItemPrice { get; set; }
    }
}
  • InheritsOrdetItems はキーが文字列で、値が ItemDetail オブジェクトの辞書(Dictionary<string, ItemDetail>)型として定義しています。
  • ItemDetail クラスは itemName と itemPrice の2つのプロパティを持っています。

値の設定は下記のように行います。

csharp
using System;
using System.Collections.Generic;

namespace AdditionalPropertiesJson
{
    class Program
    {
        static void Main(string[] args)
        {
            var response = new HogeResponse
            {
                InheritsOrdetItems = new Dictionary<string, ItemDetail>
                {
                    { "SampleKey01", new ItemDetail { ItemName = "りんご", ItemPrice = 250 } },
                    { "SampleKey02", new ItemDetail { ItemName = "バナナ", ItemPrice = 150 } },
                    { "SampleKey03", new ItemDetail { ItemName = "オレンジ", ItemPrice = 200 } }
                }
            };

            // 値が正しくセットされているか確認するための出力
            foreach (var item in response.InheritsOrdetItems)
            {
                Console.WriteLine($"{item.Key} -> Name: {item.Value.ItemName}, Price: {item.Value.ItemPrice}");
            }
        }
    }

    public class HogeResponse
    {
        public Dictionary<string, ItemDetail> InheritsOrdetItems { get; set; }
    }

    public class ItemDetail
    {
        public string ItemName { get; set; }
        public int ItemPrice { get; set; }
    }
}

記事内のソースコードはGitに登録しています。
https://github.com/yutaka-art/Samples

GitHubで編集を提案

Discussion