JSON และ Serde
TypeScript types vs Rust structs
หัวข้อที่มีชื่อว่า “TypeScript types vs Rust structs”ใน TypeScript คุณกำหนด type หรือ interface สำหรับ API payload แล้วใช้ zod (หรือ library คล้าย ๆ กัน) ทำ runtime validation ส่วนใน Rust struct เป็นทั้ง type และ validator ในตัว — serde derive ทั้ง serialization และ deserialization ให้ตั้งแต่ compile time และ field ที่หายไปหรือผิด type จะโดนปฏิเสธตั้งแต่ขั้น deserialization โดยอัตโนมัติ
import { z } from 'zod';
// Define schema + type togetherconst UserSchema = z.object({ id: z.number(), name: z.string(), email: z.string().email(),});
type User = z.infer<typeof UserSchema>;
// Validate at runtimeconst parsed = UserSchema.parse(rawJson); // throws ZodError if invaliduse 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 automaticallylet user: User = serde_json::from_str(raw_json)?; // returns Err if invalidJson<T> ใน Axum — request และ response
หัวข้อที่มีชื่อว่า “Json<T> ใน Axum — request และ response”Json<T> ของ Axum ทำหน้าที่ทั้ง extractor และ responder เป็นสะพานเชื่อมระหว่าง HTTP body กับ Rust type เมื่อวางเป็น parameter จะ deserialize request body ให้ และเมื่อใช้เป็น return value จะ serialize response ให้
// Express — parse body + respond with JSONapp.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});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 responseasync 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))}การเปลี่ยนชื่อและ skip fields ด้วย Serde
หัวข้อที่มีชื่อว่า “การเปลี่ยนชื่อและ skip fields ด้วย Serde”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,}ลองใช้งาน — serde serialize / deserialize
หัวข้อที่มีชื่อว่า “ลองใช้งาน — serde serialize / deserialize”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"), }; let json = serde_json::to_string_pretty(&user).unwrap(); println!("{}", json);
// Deserialize JSON string -> struct let parsed: User = serde_json::from_str(json_str).unwrap(); println!("{:?}", parsed);}Compiling…