JSON to Rust Struct — JSON から Rust Struct 型を生成
serde を使って JSON から Rust struct 型を生成します。null 許容フィールドには Option、snake_case には rename_all、欠落しうるフィールドには #[serde(default)]——ブラウザ内で完結、アップロード不要。
JSON to Rust Struct
Convert JSON to Rust struct with serde derive macros. Works entirely in your browser.
Rust の型システムは厳格さで有名ですが、serde は JSON を現実的に扱えるようにする橋渡しの役割を担っています。Deserialize derive マクロは、パース処理を代わりに書いてくれるコードジェネレータそのものです。#[derive(Deserialize)] を付けた struct は、serde_json::from_str::<MyStruct>(&json_str)? という 1 回の呼び出しだけで JSON 文字列からインスタンス化でき、しかもコンパイラはコードが動く前にすべてのフィールド型がデシリアライズ可能かどうかを検査します。JSON to Rust Struct ジェネレータは、サンプルの JSON レスポンスを走査して、それに一致する struct を出力します——手作業なら 5 分(フィールドを camelCase から snake_case に直し、Option にするか否かを選び、既定値を設定する)、機械なら 5 ミリ秒で済む作業です。
Rust 特有で分かりにくいのは、命名規則の橋渡しと、default と optional の区別です。Rust の慣習は snake_case(user_id)ですが、JSON の慣習はさまざまです——多くの API は camelCase(userId)を使い、一部は PascalCase(UserId)を使い、社内 API では最初から snake_case のこともあります。serde の rename_all 属性は、この大文字小文字の変換をまとめて処理します。Option と #[serde(default)] の区別はもっと微妙です。Option<T> はフィールドが存在するものの値が null である場合をカバーし、#[serde(default)] はフィールドが JSON オブジェクトから完全に欠落している場合をカバーします。多くの API では、この両方が必要になります。
struct を生成したあとで最もよくある次の手順は、API を扱うために reqwest や ureq に渡すことです。.json::<MyStruct>() でレスポンスボディを直接デシリアライズし、パースは serde に任せます。Tokio を使った非同期 Rust では、共有された可変アクセスのために struct を Arc<RwLock<MyStruct>> で包みます。データベースに接続する場合は、serde の derive と並べて #[derive(sqlx::FromRow)] や Diesel の #[derive(Queryable)] を追加します。生成された struct はデータの契約であり、非同期ランタイム、データベースのマッピング、エラーハンドリングこそが開発者の手で補う部分です。
使い方
JSON を貼り付ける
JSON オブジェクト、またはオブジェクトの配列を入力欄にドロップします。ジェネレータは構造を走査し、ルートに対して Rust struct を出力し、各オブジェクトの形ごとにネストした struct を生成します。
serde のオプションを選ぶ
camelCase の JSON キーには `rename_all = camelCase` を、null 許容フィールドには `Option<T>` を、一部の API レスポンスで欠落しうるフィールドには `#[serde(default)]` を切り替えて指定できます。
.rs ファイルをコピーまたはダウンロード
Rust struct をクリップボードにコピーするか、.rs ファイルとしてダウンロードできます。出力の先頭には `use serde::{Deserialize, Serialize};` が含まれるため、モジュールに貼り付ければそのままコンパイルできます。
よくある質問
なぜ Deserialize と Serialize を derive するのですか?
serde の `#[derive(Deserialize, Serialize)]` は、Rust で JSON の自動シリアライズを有効にする標準的な方法です。`Deserialize` は実行時に JSON を struct へパースするために必須です。`Serialize` は任意ですが、struct が正しくラウンドトリップするよう既定で含めています。
rename_all は JSON キーの大文字小文字をどう扱いますか?
struct レベルに `#[serde(rename_all = "camelCase")]` を書くと、Rust の snake_case のフィールド名(`user_id`)を JSON の camelCase のキー(`userId`)に対応付けるよう serde に指示できます。このリネームはすべてのフィールドに適用されます。個別のフィールドは `#[serde(rename = "custom_name")]` で上書きできます。
null のフィールドと欠落したフィールドはどう扱われますか?
サンプルで null になっているフィールドは `Option<T>` になります。配列の一部の要素で欠落しているフィールドには、`Option<T>` に加えて `#[serde(default)]` が付きます。これにより、JSON にキーが無い場合はパースエラーではなく `None` としてデシリアライズされます。
enum や tagged union はどうなりますか?
ジェネレータは、既知の文字列値の集合から Rust の enum を推論しません。"active"、"pending"、"closed" のいずれかを取る status フィールドは `String` として出力されます。enum と serde の tag は、生成後に手動で定義してください。
chrono や uuid の型には対応していますか?
既定では、ISO 8601 の日付文字列は `String` になります。「chrono」を有効にすると `chrono::NaiveDateTime` を出力し、ISO 8601 形式のための `serde::with` アノテーションを追加します。UUID 文字列も既定では `String` です——使う場合は `uuid` crate を手動で追加してください。
制限事項
- serde flatten には未対応ジェネレータは、親の階層にインライン展開すべきネストした JSON オブジェクトに対して `#[serde(flatten)]` を使いません。ネストが深いものの、アプリケーション側ではフラットに扱う API の場合は、手動で flatten を追加してください。
- ジェネリック型パラメータには未対応出力は具体的なフィールド型を持つ具体的な struct です。多態的な JSON レスポンス(例:`{ "type": "image", "data": ... }`)には、serde の internally tagged 表現を用いた enum を手書きする必要があります。
- 借用は考慮されないすべてのフィールド型は自身のデータを所有します(String、Vec など)。ライフタイムや借用は使いません。`Cow<'_, str>` によるゼロコピーのデシリアライズを行う場合は、ライフタイムと `#[serde(borrow)]` アノテーションを手動で追加してください。
プラットフォーム別の注意点
- macOS
- RustRover、rust-analyzer を入れた VS Code、Rust 対応の vim は、いずれも生成された struct をそのまま扱えます。API を調べている最中に、サンプルレスポンスから一回限りの生成を行うにはブラウザツールが便利です。
- Windows
- 生成された struct は、どの Rust ツールチェーンでもコンパイルできます。本格的な IDE を開かずに一回限りの struct 生成をしたいときは、ブラウザツールが便利です。
- Linux
- コマンドライン作業では、`quicktype --lang rust` や `serde-generate` が同様の出力を生成します。Rust をインストールできない環境での一回限りの生成には、ブラウザツールが適しています。
- Web
- 完全にクライアントサイドで動作します。生成は数ミリ秒で終わります。