Penanganan Error
Termasuk bagian Dasar-Dasar Express dalam perjalanan Node.js di Coddy. Pelajaran 15 dari 20.
Ketika sebuah route melempar error, Express menampilkan halaman error bawaannya, yang bukan JSON dan menampilkan detail yang ditujukan untukmu.
app.get('/api/fines/:member', (req, res) => {
throw new Error('Fines database is down');
});
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Try again later' });
});Middleware dengan empat argumen, (err, req, res, next), adalah penangan error. Express menghitung jumlah argumen: dengan tiga argumen, middleware tersebut adalah middleware biasa, dan error akan melewatinya. Ketika sebuah route melempar error, Express melewati middleware biasa dan memanggil penangan error dengan error tersebut. Tambahkan penangan ini paling akhir, setelah penangan 404. Catat detailnya untuk dirimu sendiri; kirim pesan singkat kepada client.
Nilai ?by= yang tidak valid adalah kesalahan pengunjung, jadi tetap menghasilkan 400. Error ditujukan untuk hal yang tidak dapat diperbaiki pengunjung, seperti resep yang disimpan tanpa jumlah porsinya.
Tantangan
MudahGET /api/recipes/:id/scale?by=2memberikan jawaban{ "title", "servings" }, jumlah porsi dikalikan.- Faktor yang bukan angka positif:
400dengan{ "error": "Scale by a positive number" }. - Resep tanpa
servingsmemunculkanRecipe <id> has no servings. - Penangan error mencatat error dan memberikan jawaban
500dengan{ "error": "Something went wrong" }.
Kirim ?by=2 dan ?by=lots. Lalu kirim { "title": "Toast" } ke /api/recipes dan skalakan resep 5.
Coba sendiri
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.json());
app.use(express.static('public'));
const escapeHtml = (text) =>
text
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"');
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') mengirim teks biasa, sehingga setiap judul tampil di baris tersendiri.
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.post('/api/recipes', (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);
});
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.use((req, res) => {
if (req.path.startsWith('/api/')) {
res.status(404).json({ error: 'Not found' });
return;
}
res.status(404).send('<h1>Page not found</h1><p><a href="/">Back to Recipe Box</a></p>');
});
app.listen(3000, () => {
console.log('Recipe Box is running on port 3000');
});
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Dasar-Dasar Express
Latihan sendiri: Playground Express