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

โครงสร้างโปรเจกต์

ทุกโปรเจกต์ Node.js เริ่มด้วย package.json ส่วนของเทียบเท่าใน Rust คือ Cargo.toml ซึ่งประกาศชื่อ crate, version และ dependency ตัว Cargo เองเป็นทั้ง package manager และ build tool — ไม่ต้องแยก npm กับ tsc กับ ts-node

flowchart TD
  root["my-api/ (Express/NestJS project)"] --> pkg["package.json — dependencies + scripts"]
  root --> tsc["tsconfig.json — TypeScript compiler config"]
  root --> src["src/"]
  src --> main["main.ts — entry point"]
  src --> appmod["app.module.ts — (NestJS) root module"]
  src --> users["users/"]
  users --> ctrl["users.controller.ts"]
  users --> svc["users.service.ts"]
  users --> mod["users.module.ts"]
  root --> dist["dist/ — compiled output"]
Express/NestJS project layout
flowchart TD
  root["my-api/ (Axum project)"] --> toml["Cargo.toml — dependencies + metadata (= package.json)"]
  root --> lock["Cargo.lock — lockfile (= package-lock.json)"]
  root --> src["src/"]
  src --> main["main.rs — entry point"]
  src --> routes["routes/"]
  routes --> rmod["mod.rs — route definitions"]
  src --> handlers["handlers/"]
  handlers --> husers["users.rs — handler functions"]
  src --> models["models.rs — serde structs (request/response types)"]
  src --> state["state.rs — shared AppState"]
  src --> errors["errors.rs — custom error types"]
Axum project layout
[package]
name = "my-api"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-rustls", "uuid"] }
uuid = { version = "1", features = ["v4", "serde"] }
thiserror = "1"

เทียบกับ npm install express คุณประกาศทุกอย่างในไฟล์เดียวและ Cargo จะแก้ไข dependency graph, compile ทุกอย่าง และ link เข้าด้วยกัน — ไม่ต้องมีขั้นตอน build แยกต่างหาก

use axum::Router;
use std::net::SocketAddr;
mod errors;
mod handlers;
mod models;
mod routes;
mod state;
#[tokio::main]
async fn main() {
// initialise structured logging
tracing_subscriber::fmt()
.with_env_filter("my_api=debug,tower_http=debug")
.init();
let state = state::AppState::new().await;
let app = routes::create_router(state);
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
tracing::info!("Listening on {addr}");
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

#[tokio::main] คือ macro ที่ wrap main ใน Tokio async runtime — เทียบได้กับ event loop ของ Node ที่เริ่มต้นโดยอัตโนมัติ

Node/TSRust/Axum
package.jsonCargo.toml
npm installcargo add / cargo build
ts-node src/main.tscargo run
tsc --buildcargo build --release
nodemoncargo-watch -x run
src/app.tssrc/main.rs
process.env.PORTstd::env::var("PORT")

รันบนเครื่องของคุณ — นี่คือบทเรื่องโครงสร้างโปรเจกต์ ไม่มี snippet ที่รันใน browser ได้ สร้างโปรเจกต์ด้วย cargo new my-api และเพิ่ม dependencies ด้วย cargo add axum tokio serde serde_json

อะไรคือสิ่งเทียบเท่า `package.json` ใน Rust?
`#[tokio::main]` ทำหน้าที่อะไร?
คำสั่งใดรัน Axum project ระหว่าง development?