Serdeとは何か
WebアプリケーションやAPIを開発していると、JSONデータを扱う場面が頻繁にあります。RustではSerdeというクレートがデファクトスタンダードになっており、構造体とJSONなどの形式を相互変換する処理を非常に簡潔に記述できます。
SerdeはSerialize(シリアライズ:RustデータをJSONなどに変換)とDeserde(デシリアライズ:JSONなどをRustデータに変換)の2方向をカバーしています。
この記事ではSerdeの基本的な使い方から、フィールド名の変換・デフォルト値の設定・ネストした構造体の扱いまでを順を追って解説します。
セットアップ
まずCargo.tomlにSerdeとJSON用のクレートserde_jsonを追加します。
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
features = ["derive"]を指定することで、マクロを使った自動導出(derive)が使えるようになります。
基本的なシリアライズ・デシリアライズ
構造体へのderive
Serdeで最もよく使うパターンが#[derive(Serialize, Deserialize)]アトリビュートです。構造体に付与するだけで変換処理が自動生成されます。
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
構造体 → JSON(シリアライズ)
serde_json::to_string()で構造体をJSON文字列に変換できます。
fn main() {
let user = User {
id: 1,
name: String::from("Alice"),
email: String::from("alice@example.com"),
};
let json = serde_json::to_string(&user).unwrap();
println!("{}", json);
// {"id":1,"name":"Alice","email":"alice@example.com"}
// 見やすく整形したい場合
let pretty = serde_json::to_string_pretty(&user).unwrap();
println!("{}", pretty);
}
JSON → 構造体(デシリアライズ)
serde_json::from_str()でJSON文字列を構造体に変換できます。
fn main() {
let json = r#"{"id":2,"name":"Bob","email":"bob@example.com"}"#;
let user: User = serde_json::from_str(json).unwrap();
println!("{:?}", user);
// User { id: 2, name: "Bob", email: "bob@example.com" }
}
よく使うSerdeアトリビュート
フィールド名をスネークケース ↔ キャメルケースに変換する
APIのレスポンスではcamelCaseのキー名が一般的です。#[serde(rename_all = "camelCase")]を使えば、Rust側はスネークケースのまま扱えます。
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Article {
article_id: u32,
title: String,
published_at: String,
}
fn main() {
let article = Article {
article_id: 10,
title: String::from("Rust入門"),
published_at: String::from("2026-08-16"),
};
let json = serde_json::to_string(&article).unwrap();
println!("{}", json);
// {"articleId":10,"title":"Rust入門","publishedAt":"2026-08-16"}
}
特定のフィールドをスキップする
パスワードなど、シリアライズ時に含めたくないフィールドには#[serde(skip_serializing)]を使います。
#[derive(Debug, Serialize, Deserialize)]
struct Account {
id: u32,
username: String,
#[serde(skip_serializing)]
password_hash: String,
}
デフォルト値を設定する
JSONにキーが存在しない場合に使うデフォルト値は#[serde(default)]で設定できます。
#[derive(Debug, Serialize, Deserialize)]
struct Config {
host: String,
#[serde(default = "default_port")]
port: u16,
}
fn default_port() -> u16 {
8080
}
fn main() {
let json = r#"{"host":"localhost"}"#;
let config: Config = serde_json::from_str(json).unwrap();
println!("{:?}", config);
// Config { host: "localhost", port: 8080 }
}
ネストした構造体の扱い
構造体が別の構造体をフィールドに持つ場合も、両方にderiveを付ければ自動的にネストされたJSONとして変換されます。
#[derive(Debug, Serialize, Deserialize)]
struct Address {
city: String,
zip: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct Person {
name: String,
address: Address,
}
fn main() {
let json = r#"{
"name": "Carol",
"address": {
"city": "Tokyo",
"zip": "100-0001"
}
}"#;
let person: Person = serde_json::from_str(json).unwrap();
println!("{}", person.address.city); // Tokyo
}
エラーハンドリング
実際のコードではunwrap()の代わりに?演算子やmatchでエラーを適切に処理しましょう。
use serde_json::Error;
fn parse_user(json: &str) -> Result<User, Error> {
let user: User = serde_json::from_str(json)?;
Ok(user)
}
fn main() {
let invalid_json = r#"{"id": "not_a_number"}"#;
match parse_user(invalid_json) {
Ok(user) => println!("{:?}", user),
Err(e) => eprintln!("パースエラー: {}", e),
}
}
まとめ
SerdeはRustにおけるデータ変換の中心的なクレートです。今回のポイントを振り返ります。
| 操作 | 関数・アトリビュート |
|---|---|
| シリアライズ | serde_json::to_string() |
| デシリアライズ | serde_json::from_str() |
| フィールド名変換 | #[serde(rename_all = "camelCase")] |
| フィールドのスキップ | #[serde(skip_serializing)] |
| デフォルト値 | #[serde(default = "関数名")] |
ActixやAxumなどのWebフレームワークでもSerdeは内部的に使われており、使い方を覚えておくと実践的なRust開発で大きな助けになります。ぜひ手元で動かして試してみてください。