Menu
CoddyTech

Đọc nội dung yêu cầu

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 15 trên 23.

Một yêu cầu POST gửi dữ liệu trong phần thân, và Express sẽ không đọc phần thân trừ khi bạn yêu cầu.

app.use(express.json());

app.post('/api/loans', (req, res) => {
    const { bookId, member } = req.body;
    res.status(201).json({ bookId, member, due: '2026-11-08' });
});

GET yêu cầu một thứ gì đó, còn POST gửi dữ liệu để tạo một thứ gì đó. express.json() là middleware đọc mọi phần thân JSON vào req.body. Nếu thiếu nó, req.body sẽ là undefined. Một tuyến tạo ra thứ gì đó sẽ trả lời bằng mã 201 cùng với thứ đã tạo.

Hãy kiểm tra phần thân trước khi lưu. Thiếu trường là lỗi của máy khách, vì vậy hãy trả lời bằng mã 400 và không lưu gì cả.

challenge icon

Thử thách

Dễ

Khách truy cập có thể thêm công thức nấu ăn của riêng mình. Một chương trình gửi công thức mới dưới dạng JSON trong phần thân của yêu cầu POST, rồi API của bạn lưu công thức đó.

  1. Trong server.js, thêm express.json() cùng các dòng app.use khác, phía trên các route, để phần thân JSON có trong req.body.
  2. Thêm một route cho các yêu cầu POST đến /api/recipes. Route này đọc title và tags từ phần thân, ví dụ {"title": "Miso Soup", "tags": ["vegan", "soup"]}.
  3. Route tạo công thức mới với id là số tiếp theo: bốn công thức có id từ 1 đến 4, nên công thức mới đầu tiên sẽ có id 5. Công thức giữ nguyên tiêu đề và thẻ được gửi đến. Nếu không có tags, hãy dùng danh sách rỗng [].
  4. Route thêm công thức vào mảng recipes, để GET /api/recipes liệt kê công thức đó. Sau đó, route phản hồi với trạng thái 201 và công thức mới dưới dạng JSON: {"id": 5, "title": "Miso Soup", "tags": ["vegan", "soup"]}
  5. Nếu phần thân không có title, route không lưu gì và phản hồi với trạng thái 400 cùng JSON này: {"error": "A recipe needs a title"}

Thử nhé: Nhấn Chạy. Chọn POST trong bộ chọn phương thức, nhập /api/recipes làm đường dẫn, rồi nhập {"title": "Miso Soup", "tags": ["vegan", "soup"]} vào ô phần thân. Bạn sẽ thấy trạng thái 201 và công thức có "id": 5. Chọn GET và gửi /api/recipes: sẽ có năm công thức, trong đó Miso Soup nằm cuối cùng. Sau đó, gửi POST {"tags": ["dinner"]} đến /api/recipes: trạng thái 400 và {"error":"A recipe needs a title"}. GET /api/recipes vẫn liệt kê năm công thức.

Tự làm thử

import { escapeHtml } from './html.js';
import express from 'express';
import { randomUUID } from 'node:crypto';
import { recipes } from './data.js';

const app = express();

app.use((req, res, next) => {
    console.log(`${req.method} ${req.url}`);
    next();
});

app.use((req, res, next) => {
    res.set('X-Request-Id', randomUUID());
    next();
});

app.use(express.static('public'));

app.get('/', (req, res) => {
    const items = recipes.map((r) => `<li><a href="/recipes/${r.id}">${escapeHtml(r.title)}</a></li>`);
    res.send(`<link rel="stylesheet" href="/style.css"><h1>Recipe Box</h1><ul>${items.join('')}</ul>`);
});

// type('text') gửi văn bản thuần, nên mỗi tiêu đề hiển thị trên một dòng riêng.
app.get('/recipes', (req, res) => {
    const { tag } = req.query;
    const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
    res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});

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

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

app.get('/api/recipes/: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);
});

app.get('/about', (req, res) => {
    res.send('Recipe Box collects family recipes.');
});

app.get('/menu', (req, res) => {
    res.redirect(301, '/recipes');
});

app.get('/menu/:id', (req, res) => {
    res.redirect(301, `/recipes/${req.params.id}`);
});

app.listen(3000, () => {
    console.log('Recipe Box is running on port 3000');
});
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