ข้ามไปยังเนื้อหา

JSON และ Serde

ใน TypeScript คุณกำหนด type หรือ interface สำหรับ API payload แล้วใช้ zod (หรือ library คล้าย ๆ กัน) ทำ runtime validation ส่วนใน Rust struct เป็นทั้ง type และ validator ในตัวserde derive ทั้ง serialization และ deserialization ให้ตั้งแต่ compile time และ field ที่หายไปหรือผิด type จะโดนปฏิเสธตั้งแต่ขั้น deserialization โดยอัตโนมัติ

TypeScript
import { z } from 'zod';
// Define schema + type together
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
// Validate at runtime
const parsed = UserSchema.parse(rawJson); // throws ZodError if invalid
Rust
use serde::{Deserialize, Serialize};
// Derive gives you compile-time serialization AND runtime validation
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
// Deserializing validates structure and types automatically
let user: User = serde_json::from_str(raw_json)?; // returns Err if invalid

Json<T> ของ Axum ทำหน้าที่ทั้ง extractor และ responder เป็นสะพานเชื่อมระหว่าง HTTP body กับ Rust type เมื่อวางเป็น parameter จะ deserialize request body ให้ และเมื่อใช้เป็น return value จะ serialize response ให้

TypeScript
// Express — parse body + respond with JSON
app.post('/users', express.json(), async (req, res) => {
const user: CreateUser = CreateUserSchema.parse(req.body);
const saved = await db.save(user);
res.status(201).json(saved); // manual serialization call
});
Rust
use axum::{http::StatusCode, Json};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct CreateUser { name: String, email: String }
#[derive(Serialize)]
struct User { id: u32, name: String, email: String }
// Json<CreateUser> deserializes the body
// (StatusCode, Json<User>) serializes the response
async fn create_user(
Json(payload): Json<CreateUser>,
) -> (StatusCode, Json<User>) {
let user = User { id: 1, name: payload.name, email: payload.email };
(StatusCode::CREATED, Json(user))
}

Serde รองรับการแปลง field เหมือนกับ class-transformer ของ TypeScript หรือ zod .transform():

use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct User {
id: u32,
#[serde(rename = "fullName")]
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
avatar_url: Option<String>,
#[serde(skip_deserializing)]
created_at: String,
}

Snippet ด้านล่างรันได้ทั้งหมดในเบราว์เซอร์ ไม่ได้ใช้ Axum (ไม่ต้องมี server) — แค่ serde และ serde_json ซึ่งมีอยู่บน Rust Playground

use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
fn main() {
// Serialize struct -> JSON string
let user = User {
id: 1,
name: String::from("Alice"),
email: String::from("[email protected]"),
};
let json = serde_json::to_string_pretty(&user).unwrap();
println!("{}", json);
// Deserialize JSON string -> struct
let json_str = r#"{"id":2,"name":"Bob","email":"[email protected]"}"#;
let parsed: User = serde_json::from_str(json_str).unwrap();
println!("{:?}", parsed);
}
derive macros สองตัวใดที่ serde ให้สำหรับ JSON serialization?
เมื่อ `Json<T>` ใช้เป็น **parameter** ของ Axum handler จะทำอะไร?
attribute ของ serde ตัวใดซ่อน field จาก JSON output เมื่อค่าเป็น `None`?