Página de búsqueda
Parte de la sección Conceptos básicos de Express del Journey de Node.js de Coddy. Lección 23 de 23.
Una página de búsqueda es un formulario, y el servidor responde a ella como a cualquier otra solicitud GET.
<form action="/books" method="get">
<input name="author">
<button>Find</button>
</form>Al enviar este formulario, el navegador va a /books?author= seguido de lo que se escribió en el campo llamado author. La ruta lo lee de req.query. Escribir la palabra de nuevo como value del campo hace que siga visible después de la búsqueda; proviene del visitante, así que escápala.
Desafío
FácilRecipe Box incorpora una página de búsqueda. Un visitante escribe una palabra y la página muestra las recetas cuyo título la contiene.
- En
server.js, encima del controlador 404, añade una ruta asíncrona para/search. Lee la palabra dereq.query.qo usa una cadena vacía si no hay ninguna. - La página siempre tiene un formulario de búsqueda:
<form action="/search" method="get">con un campo de texto llamadoqy un botón. Al enviarlo, se abre/search?q=seguido de la palabra. - El campo muestra la palabra que se buscó: después de buscar
curry, el campo contienecurry. Escribe la palabra en el atributovaluedel campo, pasándola porescapeHtml, porque proviene del visitante. - Debajo del formulario, muestra un enlace por cada receta de
loadRecipes()cuyo título contenga la palabra, sin distinguir entre mayúsculas y minúsculas: tantosoupcomoSOUPencuentran Tomato Soup. Cada enlace lleva a la página de la receta y muestra su título escapado, como en la página de inicio:<a href="/recipes/1">Tomato Soup</a>. - Cuando se haya buscado una palabra y ningún título la contenga, muestra el texto
No recipes founden lugar de la lista.
Pruébalo: Pulsa Ejecutar y envía /search: la página muestra el formulario vacío. Escribe SOUP en el campo y pulsa el botón. La página muestra Tomato Soup y el campo sigue mostrando SOUP. Busca pizza: No recipes found. Busca fish: Fish & Chips, correctamente mostrado. Después, envía por POST {"title": "Pea Soup", "tags": ["soup"]} a /api/recipes y vuelve a buscar soup: Pea Soup también aparece en la lista.
Pruébalo tú mismo
import { escapeHtml } from './html.js';
import { dayOfYear } from './day-of-year.js';
import express from 'express';
import { randomUUID } from 'node:crypto';
import { recipes } from './data.js';
import recipesRouter, { loadRecipes } 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') envía texto sin formato, por lo que cada título aparece en su propia línea.
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('/api/today', async (req, res) => {
const day = dayOfYear(req.query.date);
if (day === null) {
res.status(400).json({ error: 'Use a date like 2026-03-01' });
return;
}
const recipes = await loadRecipes();
res.json(recipes[day % recipes.length]);
});
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');
});
Todas las lecciones de Conceptos básicos de Express
Practica por tu cuenta: Playground de Express