Menu
CoddyTech

Các tuyến bất đồng bộ

Thuộc phần Kiến thức cơ bản về Express trong hành trình Node.js của Coddy. Bài học 21 trên 23.

Mảng sẽ biến mất khi máy chủ khởi động lại. Tệp sẽ lưu giữ dữ liệu.

import { readFile } from 'node:fs/promises';

app.get('/api/forecast', async (req, res) => {
    const text = await readFile('data/forecast.json', 'utf8');
    res.json(JSON.parse(text));
});

Một route có thể là hàm async chờ bằng await, trong trường hợp này là chờ readFile từ node:fs/promises. Express 5 theo dõi promise mà route trả về: nếu promise bị từ chối vì tệp không tồn tại hoặc JSON bị lỗi, lỗi sẽ được chuyển đến trình xử lý lỗi của bạn, giống như khi có lệnh throw.

Nếu không có await, bạn sẽ giữ một promise thay vì dữ liệu, và res.json(promise) sẽ gửi {}. Tệp data/recipes.json mới chứa bốn công thức.

challenge icon

Thử thách

Dễ

Mảng trong bộ nhớ sẽ mất mỗi khi máy chủ khởi động lại. Thay vào đó, hãy lưu các công thức trong tệp data/recipes.json, tệp này đã chứa bốn công thức.

  1. Trong routes/recipes.js, nhập readFile và writeFile từ node:fs/promises, đồng thời ngừng nhập recipes từ ../data.js.
  2. Viết một hàm trợ giúp duy nhất, loadRecipes(), là hàm bất đồng bộ đọc data/recipes.json và trả về danh sách đã phân tích cú pháp. Các bài học tiếp theo sẽ dùng tên này.
  3. Đặt mọi tuyến trong tệp thành async, và bắt đầu mỗi tuyến bằng cách chờ loadRecipes(): /tags, danh sách, một công thức, tuyến POST và tuyến scale.
  4. Trong tuyến POST, sau khi thêm công thức mới vào danh sách, hãy ghi toàn bộ danh sách trở lại data/recipes.json bằng writeFile, dưới dạng văn bản JSON.
  5. Tuyến scale vẫn ném lỗi nếu công thức không có số khẩu phần, giờ đây là từ bên trong một hàm bất đồng bộ. Express 5 vẫn chuyển lỗi đó đến trình xử lý lỗi như trước, nên máy chủ vẫn phản hồi với mã 500 và {"error": "Something went wrong"}. Đừng bắt lỗi trong tuyến.

Thử nhé: Nhấn Chạy và gửi /api/recipes: vẫn là bốn công thức đó, giờ được đọc từ tệp. Chọn POST và gửi {"title": "Gazpacho", "tags": ["vegan", "soup"]} đến /api/recipes: mã trạng thái 201 và công thức có "id": 5. Gửi /api/recipes/5: Gazpacho. Gửi /api/recipes/99: mã trạng thái 404. Sau đó POST {"title": "Toast"}, công thức này không có số khẩu phần và trở thành công thức số 6, rồi gửi /api/recipes/6/scale?by=2: mã trạng thái 500 và {"error":"Something went wrong"}. Nếu bạn thấy {} thay vì dữ liệu, tức là còn thiếu await.

Tự làm thử

import express from 'express';
import { recipes } from '../data.js';

const router = express.Router();

// Mỗi thẻ xuất hiện một lần, theo thứ tự bảng chữ cái.
router.get('/tags', (req, res) => {
    const tags = new Set(recipes.flatMap((recipe) => recipe.tags));
    res.json([...tags].sort());
});

router.get('/', (req, res) => {
    res.json(recipes);
});

router.get('/:id', (req, res) => {
    const recipe = recipes.find((r) => r.id === Number(req.params.id));
    if (!recipe) {
        res.status(404).json({ error: 'No such recipe' });
        return;
    }
    res.json(recipe);
});

router.post('/', (req, res) => {
    const { title, tags } = req.body;
    if (!title) {
        res.status(400).json({ error: 'A recipe needs a title' });
        return;
    }
    const recipe = { id: recipes.length + 1, title, tags: tags ?? [] };
    recipes.push(recipe);
    res.status(201).json(recipe);
});

router.get('/:id/scale', (req, res) => {
    const recipe = recipes.find((r) => r.id === Number(req.params.id));
    if (!recipe) {
        res.status(404).json({ error: 'No such recipe' });
        return;
    }
    const by = Number(req.query.by);
    if (!Number.isFinite(by) || by <= 0) {
        res.status(400).json({ error: 'Scale by a positive number' });
        return;
    }
    if (!recipe.servings) {
        throw new Error(`Recipe ${recipe.id} has no servings`);
    }
    res.json({ title: recipe.title, servings: recipe.servings * by });
});

export default router;
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Kiến thức cơ bản về Express

Tự luyện tập: Playground Express