跳到主要内容

坚固可靠:JSON To Rust Serde结构 — Numio

根据 JSON 示例生成带 serde Serialize 和 Deserialize derive 的 Rust struct。字段变为 snake_case 并附带 rename_all 属性,数组中部分元素缺少的键变为 Option<T>,null 值变为 serde_json::Value。

在 reqwest 客户端中用 serde_json 反序列化第三方 API 响应之前,先为其定义类型。

JSON

Rust Serde

适用场景

  • 在 reqwest 客户端中用 serde_json 反序列化第三方 API 响应之前,先为其定义类型。
  • 为 Rust CLI 或 Axum 服务中的 JSON 配置文件或测试数据文件编写 struct。

使用方法

  1. 粘贴 JSON 示例;如果某字段是可选的,请同时包含有该字段和没有该字段的数组元素。
  2. 打开设置,选择与 JSON 中键的写法一致的 Property Name Format(默认 camelCase)。它决定 #[serde(rename_all = ...)];不符合的键会加上 #[serde(rename = ...)]。
  3. 复制代码,并按生成的 use 语句在 Cargo.toml 中加入 serde(启用 derive)、serde_derive 和 serde_json。

JSON 输入

{
  "orderId": "A-1001",
  "total": 19.5,
  "paid": true,
  "coupon": null,
  "items": [
    { "sku": "PEN-01", "qty": 2 },
    { "sku": "BOOK-7", "qty": 1, "giftWrap": true }
  ]
}

Rust struct(serde)

use serde_derive::Deserialize;
use serde_derive::Serialize;
use serde_json::Value;

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Root {
    pub order_id: String,
    pub total: f64,
    pub paid: bool,
    pub coupon: Value,
    pub items: Vec<Item>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Item {
    pub sku: String,
    pub qty: i64,
    pub gift_wrap: Option<bool>,
}

功能与限制

生成在浏览器中通过 json_typegen WebAssembly 模块进行,不会向服务器发送任何内容。

整数变为 i64,小数变为 f64。null 和空数组得到 serde_json::Value 和 Vec<Value>;请替换为 Option<String> 等具体类型。

Rust 关键字会被重命名:名为 type 的键变为 type_field,并带 #[serde(rename = "type")]。

每个 struct 除 Serialize 和 Deserialize 外还 derive 了 Default、Debug、Clone 和 PartialEq;不需要的请删除。

FAQ

Property Name Format 设置改变的是什么?

它描述的是 JSON 中键的写法,而不是 Rust 字段名。字段始终是 snake_case;该设置决定 rename_all 的取值,让 serde 把它们映射回 camelCase、kebab-case、PascalCase 等。

如何识别可选字段?

同一数组中的对象键不一致时,部分元素缺少的键变为 Option<T>。在每个示例元素中都存在的字段不会是可选的,即使你的 API 有时会省略它。

JSON 的根节点可以是数组吗?

可以。根数组会生成 pub type Root = Vec<Root2>;,以及表示元素的 struct Root2。

规范与参考资料