Resep Hari Ini
Termasuk bagian Dasar-Dasar Express dalam perjalanan Node.js di Coddy. Pelajaran 22 dari 23.
Recipe Box dapat menggunakan keterampilan rute dan membaca file yang sudah kamu kenal untuk menyajikan satu resep setiap hari. Fungsi dayOfYear yang disediakan mengubah tanggal menjadi angka: 1 Januari adalah 1 dan 1 Maret 2026 adalah 60. Tanggal yang tidak dicantumkan berarti hari ini, teks yang tidak dapat dibaca menghasilkan null.
const day = dayOfYear(req.query.date);
// ?date=2026-03-01 menghasilkan 60
// ?date=soon menghasilkan nullGunakan operator sisa untuk memilih posisi: day % recipes.length. Dengan empat resep, hari ke-60 memilih posisi nol. Muat resep di dalam permintaan agar resep yang baru diposting juga ikut. Penguraian tanggal sudah disediakan, fokuslah menyusun rutenya.
Tantangan
MudahTambahkan endpoint Resep Hari Ini ke Recipe Box. day-of-year.js yang disediakan mengekspor dayOfYear(text), yang mengembalikan nomor hari atau null untuk tanggal yang tidak valid.
- Ekspor
loadRecipesdariroutes/recipes.js. Impor keserver.js: router tetap menjadi impor default, dan{ loadRecipes }mengikutinya setelah koma. - Impor
dayOfYear. Diserver.js, tambahkan ruteasyncuntukGET /api/todaydi atas handler 404. Teruskanreq.query.dateke fungsi pembantu. - Untuk
null, kembalikan status 400 dengan{"error":"Use a date like 2026-03-01"}. - Jika tidak, gunakan
await loadRecipes()lalu kembalikanrecipes[day % recipes.length]sebagai JSON. Pertahankan rute dan handler error yang sudah ada.
Coba GET /api/today?date=2026-03-01: hasilnya resep pertama karena nomor harinya 60 dan ada empat resep. Coba ?date=soon: hasilnya error 400 di atas.
Coba sendiri
import { escapeHtml } from './html.js';
import express from 'express';
import { randomUUID } from 'node:crypto';
import { recipes } from './data.js';
import recipesRouter from './routes/recipes.js';
import reviewsRouter from './routes/reviews.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'));
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 muncul 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.use('/api/recipes', recipesRouter);
app.use('/api/recipes/:id/reviews', reviewsRouter);
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.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Something went wrong' });
});
app.listen(3000, () => {
console.log('Recipe Box is running on port 3000');
});
Semua pelajaran di Dasar-Dasar Express
Latihan sendiri: Playground Express