Khi tôi xây dựng API sản xuất đầu tiên, tôi đã sử dụng Express.js và việc thiết lập mất khoảng hai giờ: mã khởi động (boilerplate), middleware, bộ xử lý định tuyến (route handlers), cấu hình TypeScript và các script triển khai. Gần đây, tôi đã triển khai một REST API hoàn chỉnh chỉ trong 20 phút bằng NitroJs. Không có chuỗi app.use(), không có định tuyến thủ công, không có rắc rối triển khai.
Hướng dẫn này cho bạn thấy cách NitroJs loại bỏ mã khởi động đồng thời cung cấp cho bạn một backend sẵn sàng sản xuất có thể chạy ở bất cứ đâu: Node, Bun, Deno, serverless hoặc edge.
NitroJs là gì và tại sao nên sử dụng nó cho API Backend?
NitroJs là một bộ công cụ máy chủ từ hệ sinh thái UnJS xử lý backend của bạn như một thành phần bản dựng. Thay vì viết một máy chủ gắn liền với một runtime cụ thể, bạn viết các bộ xử lý định tuyến và Nitro sẽ biên dịch chúng thành một gói di động. Triển khai cùng một mã lên Node.js, Cloudflare Workers, Vercel hoặc một container Docker mà không cần thay đổi một dòng code nào.

Mô hình tư duy cốt lõi: Viết định tuyến, không phải máy chủ. Bạn tập trung vào logic API; Nitro xử lý HTTP, middleware và các thành phần liên kết nền tảng.
Ưu điểm chính cho API backend:
- Không cần cấu hình: Không cần mã khởi động
server.js - Định tuyến theo hệ thống tệp:
routes/users.get.tstrở thànhGET /users - Hỗ trợ TypeScript tự nhiên: Các loại được suy luận tự động từ các bộ xử lý
- Triển khai phổ biến: Một bản dựng, nhiều mục tiêu
- Bộ nhớ đệm tích hợp: Lưu trữ phản hồi API trong bộ nhớ, Redis hoặc Cloudflare KV
- Lớp lưu trữ: Hệ thống tệp trừu tượng hóa cho dữ liệu tạm thời
Đối với các nhà phát triển API, điều này có nghĩa là bạn triển khai nhanh hơn và ít phải tái cấu trúc hơn khi thay đổi cơ sở hạ tầng.
Bắt đầu: Cài đặt NitroJs trong 5 phút
Bước 1: Tạo dự án mẫu
# Sử dụng pnpm (khuyên dùng)
pnpm dlx giget@latest nitro nitro-api-backend
# Hoặc npm
npm create nitro@latest nitro-api-backend
# Hoặc bun
bunx giget@latest nitro nitro-api-backend
Thao tác này sẽ sao chép mẫu khởi đầu chính thức vào thư mục nitro-api-backend.
Bước 2: Khám phá cấu trúc
cd nitro-api-backend
tree -L 2
Kết quả:
├── server
│ ├── api
│ ├── routes
│ ├── tasks
│ └── middleware
├── nitro.config.ts
├── package.json
└── tsconfig.json
Các thư mục quan trọng:
server/api/: Các định tuyến API (không có giao diện người dùng)server/routes/: Các định tuyến full-stack (dành cho SSR)server/middleware/: Middleware toàn cụcserver/tasks/: Các tác vụ chạy nền
Đối với API backend thuần túy, bỏ qua routes và đặt mọi thứ vào api.
Bước 3: Chạy máy chủ phát triển
pnpm install
pnpm dev
Nitro sẽ khởi động trên http://localhost:3000 với tính năng hot reload. Chỉnh sửa một tệp, và máy chủ sẽ khởi động lại trong vòng dưới 200ms.

Xây dựng điểm cuối API đầu tiên của bạn
Bộ xử lý GET đơn giản
Tạo server/api/users.get.ts:
// server/api/users.get.ts
export default defineEventHandler(() => {
return [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
];
});
Nitro tự động phục vụ endpoint này tại GET /api/users. Wrapper defineEventHandler cung cấp an toàn kiểu (type safety) và quyền truy cập vào ngữ cảnh yêu cầu.
Định tuyến động với tham số
Tạo server/api/users/[id].get.ts:
// server/api/users/[id].get.ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id');
if (!id) {
throw createError({
statusCode: 400,
statusMessage: 'User ID is required'
});
}
return {
id: Number(id),
name: `User ${id}`,
email: `user${id}@example.com`
};
});
Truy cập GET /api/users/42 để xem { id: 42, name: "User 42", ... }.
POST với JSON Body
Tạo server/api/users.post.ts:
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
// Nitro tự động phân tích JSON
const { name, email } = body;
if (!name || !email) {
throw createError({
statusCode: 422,
statusMessage: 'Name and email are required'
});
}
// Mô phỏng việc chèn vào cơ sở dữ liệu
const newUser = {
id: Math.floor(Math.random() * 1000),
name,
email,
createdAt: new Date().toISOString()
};
return newUser;
});
Kiểm tra nó:
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","email":"charlie@example.com"}'
Phản hồi an toàn kiểu (Type-Safe)
Nitro suy luận các kiểu phản hồi từ giá trị trả về của bạn. Đối với các hợp đồng nghiêm ngặt, hãy sử dụng các kiểu rõ ràng:
// server/api/products.get.ts
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
export default defineEventHandler<Product[]>(() => {
return [
{ id: 1, name: "Laptop", price: 1299.99, inStock: true },
{ id: 2, name: "Mouse", price: 29.99, inStock: false }
];
});
Giờ đây, các client nhập điểm cuối này sẽ nhận được IntelliSense đầy đủ.
Các mô hình API nâng cao
Middleware để xác thực
Tạo server/middleware/auth.ts:
// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
const protectedRoutes = ['/api/admin', '/api/users/me'];
if (protectedRoutes.some(route => event.path.startsWith(route))) {
const token = getHeader(event, 'authorization')?.replace('Bearer ', '');
if (!token || token !== process.env.API_SECRET) {
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized'
});
}
}
});
Middleware chạy trước mọi định tuyến. Thêm nó vào nitro.config.ts:
// nitro.config.ts
export default defineNitroConfig({
srcDir: 'server',
runtimeConfig: {
apiSecret: process.env.API_SECRET
}
});
Lưu trữ phản hồi API
Lưu kết quả tính toán tốn kém trong 60 giây:
// server/api/stats.get.ts
export default defineCachedEventHandler(async () => {
const db = useStorage('data');
const users = await db.getItem('users') || [];
return {
totalUsers: users.length,
activeUsers: users.filter(u => u.lastSeen > Date.now() - 86400000).length
};
}, {
maxAge: 60, // giây
name: 'stats',
getKey: () => 'global-stats'
});
Nitro xử lý việc hủy bỏ và lưu trữ bộ nhớ đệm (bộ nhớ, Redis hoặc Cloudflare KV tùy thuộc vào mục tiêu triển khai).
Xử lý tải lên tệp
// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
const files = await readMultipartFormData(event);
if (!files?.length) {
throw createError({ statusCode: 400, statusMessage: 'No files uploaded' });
}
const storage = useStorage('uploads');
const file = files[0];
await storage.setItem(file.filename, file.data);
return { success: true, filename: file.filename };
});
Kiểm tra với:
curl -X POST http://localhost:3000/api/upload \
-F "file=@/path/to/image.jpg"
Triển khai: Từ cục bộ đến sản xuất
Tạo bản dựng cho sản xuất
pnpm build
Nitro tạo một thư mục .output với các điểm vào dành riêng cho nền tảng.
Chạy trên Node.js
node .output/server/index.mjs
Không cần node_modules—bản dựng đóng gói mọi thứ.
Triển khai tới Cloudflare Workers
# Cài đặt preset
pnpm add -D nitro-preset-cloudflare-workers
# Build với preset
NITRO_PRESET=cloudflare-workers pnpm build
# Triển khai
wrangler deploy .output
Triển khai tới Vercel (Serverless)
# Vercel tự động phát hiện Nitro
vercel
Hoặc cấu hình nitro.config.ts:
export default defineNitroConfig({
preset: 'vercel-edge'
});
Biến môi trường
Tạo .env cục bộ, sau đó sử dụng bảng điều khiển nền tảng trong môi trường sản xuất:
# .env
API_SECRET=dev-secret-key
DATABASE_URL=file:./dev.db
Truy cập trong các bộ xử lý:
const config = useRuntimeConfig();
const secret = config.apiSecret;
Các trường hợp sử dụng nâng cao
WebSockets & Sự kiện được gửi từ máy chủ (Server-Sent Events)
Nitro hỗ trợ WebSockets thông qua defineWebSocketHandler:
// server/api/ws.ts
export default defineWebSocketHandler({
open(peer) {
console.log('WebSocket connected:', peer);
},
message(peer, message) {
peer.send(`Echo: ${message.text()}`);
},
close(peer, details) {
console.log('WebSocket closed:', details);
}
});
Truy cập tại ws://localhost:3000/api/ws.
Tác vụ nền
Tạo server/tasks/cleanup.ts:
// server/tasks/cleanup.ts
export default defineCronHandler('0 2 * * *', async () => {
const db = useStorage('temp');
const keys = await db.getKeys();
for (const key of keys) {
const metadata = await db.getMeta(key);
if (metadata.expiresAt < Date.now()) {
await db.removeItem(key);
}
}
console.log('Cleanup completed');
});
Tác vụ này chạy hàng ngày vào lúc 2 giờ sáng. Triển khai tới một nền tảng có hỗ trợ cron (ví dụ: Vercel, Netlify).
Công cụ quản lý luồng công việc (Workflow Engines)
Tích hợp với useWorkflow.dev cho các hệ thống điều phối phức tạp:
// server/api/workflows/process.ts
import { createWorkflow } from '@useworkflow/sdk';
export default defineEventHandler(async (event) => {
const workflow = createWorkflow('data-pipeline', {
steps: [
{ id: 'fetch', run: 'https://api.example.com/data' },
{ id: 'transform', run: 'transform.js' },
{ id: 'store', run: async (data) => {
const storage = useStorage('results');
await storage.setItem('latest', data);
}}
]
});
await workflow.start();
return { status: 'started' };
});
Các kịch bản phát triển thực tế
Kịch bản 1: Backend cho trang web tĩnh
Triển khai một Nitro API lên Cloudflare Workers để phục vụ dữ liệu JSON cho một trang web JAMstack tĩnh. Gói miễn phí xử lý 100K yêu cầu/ngày.
Kịch bản 2: API ứng dụng di động
Xây dựng các điểm cuối REST cho ứng dụng React Native. Sử dụng tính năng xử lý CORS tích hợp của Nitro:
// nitro.config.ts
export default defineNitroConfig({
routeRules: {
'/api/**': { cors: true }
}
});
Kịch bản 3: Cổng Microservices (Microservices Gateway)
Chạy Nitro như một cổng API tổng hợp các microservices. Sử dụng $fetch để proxy các yêu cầu:
// server/api/aggregate.get.ts
export default defineEventHandler(async (event) => {
const [users, posts] = await Promise.all([
$fetch('https://users-service.internal/users'),
$fetch('https://posts-service.internal/posts')
]);
return { users, posts };
});
Kiểm thử API NitroJs của bạn với Apidog
Nitro tạo backend nhanh chóng, nhưng tốc độ sẽ vô nghĩa nếu các điểm cuối của bạn bị lỗi. Khi bạn triển khai một `POST /api/users` mới, hãy nhập định nghĩa định tuyến vào Apidog. Nó sẽ phân tích ngược kiểu trả về của bộ xử lý và tự động tạo các bài kiểm thử hợp đồng.

Chạy chúng trong CI để phát hiện các thay đổi gây lỗi trước khi nhóm frontend của bạn phải đau đầu. Nó miễn phí để bắt đầu, và đó chính là "lan can bảo vệ" mà quá trình phát triển Nitro nhanh chóng của bạn cần.
Các câu hỏi thường gặp
1. Nitro có thể thay thế hoàn toàn Express.js không?
Có. Nitro xử lý định tuyến, middleware và triển khai tốt hơn. Di chuyển bằng cách chuyển middleware của Express sang plugin Nitro và các định tuyến sang server/api/.
2. Nitro xử lý kết nối cơ sở dữ liệu như thế nào?
Sử dụng các plugin Nitro để khởi tạo các pool khi khởi động. Lớp lưu trữ trừu tượng hóa việc lưu trữ vào bộ nhớ đệm, nhưng đối với SQL, hãy tự mang ORM của riêng bạn (Prisma, Drizzle).
3. Nitro đã sẵn sàng cho môi trường sản xuất chưa?
Chắc chắn rồi. Nuxt sử dụng Nitro cho hàng triệu trang web sản xuất. Nó đã được thử nghiệm kỹ lưỡng về khả năng mở rộng.
4. Tôi có thể sử dụng Nitro với GraphQL không?
Có. Thêm bộ xử lý GraphQL vào server/api/graphql.post.ts. Sử dụng bất kỳ thư viện Node GraphQL nào—Nitro không giới hạn bạn.
5. Sự khác biệt giữa Nitro và Hono là gì?
Hono là một bộ định tuyến nhẹ. Nitro là một bộ công cụ máy chủ hoàn chỉnh với các bản dựng, preset và lưu trữ. Sử dụng Hono cho microservices, Nitro cho các backend hoàn chỉnh.
Kết luận
NitroJs định nghĩa lại việc phát triển backend bằng cách biên dịch API của bạn thành một thành phần di động. Bạn có được định tuyến theo hệ thống tệp, an toàn kiểu TypeScript và triển khai phổ biến mà không cần mã khởi động. Xây dựng REST API tiếp theo của bạn với Nitro và xác thực nó với Apidog. Bạn sẽ thấy hài lòng khi di chuyển từ Node sang edge chỉ bằng một dòng cấu hình.
