Trier du texte
Fait partie de la section API REST du Journey Node.js de Coddy. Leçon 15 sur 25.
Votre outil de suivi peut filtrer les tâches. Permettez maintenant à un client de demander des titres par ordre alphabétique sans modifier l’ordre enregistré. Une comparaison de tri renvoie un nombre négatif lorsque son premier élément doit précéder le second, un nombre positif lorsqu’il doit le suivre, et zéro lorsqu’ils sont à égalité.
const sorted = cities.toSorted((a, b) => a.name.localeCompare(b.name));Soustraire des chaînes ne permet pas d’obtenir un ordre utile. localeCompare compare plutôt le texte. toSorted renvoie un nouveau tableau, en laissant le tableau d’origine inchangé. Triez la liste filtrée afin que le filtrage et le tri fonctionnent ensemble. La leçon suivante sur le tri ajoute d’autres champs, l’ordre décroissant et la gestion des requêtes non valides.
Défi
FacileContinuez votre gestionnaire de tâches dans routes/tasks.js. Dans la route de liste, après les filtres existants, faites en sorte que ?sort=title renvoie les tâches par ordre alphabétique de titre. Sans cette valeur, conservez le comportement actuel. Ne modifiez pas l’ordre des tâches stockées.
Essayez GET /api/tasks?sort=title, puis GET /api/tasks. La deuxième liste doit toujours conserver son ordre d’origine. Le filtrage avec ?done=false&sort=title doit toujours renvoyer uniquement les tâches inachevées.
Essayez vous-même
import { Router } from 'express';
import { z } from 'zod';
import { sendError, sendInvalid } from '../errors.js';
import { nextId, tasks } from '../store.js';
const router = Router();
// Une tâche complète, telle que PUT l'envoie. .strict() rejette les champs qu'elle ne répertorie pas.
const Task = z
.object({
title: z.string().trim().min(1).max(100),
done: z.boolean(),
})
.strict();
const NewTask = Task.partial({ done: true });
const TaskChanges = Task.partial();
// Vrai si une autre tâche porte déjà ce titre, quelle que soit la casse.
const titleTaken = (title, exceptId) =>
tasks.some((t) => t.id !== exceptId && t.title.toLowerCase() === title.toLowerCase());
router.get('/', (req, res) => {
const { done, q } = req.query;
let list = tasks;
if (done !== undefined) {
if (done !== 'true' && done !== 'false') {
return sendError(res, 400, 'invalid_query', 'done must be true or false');
}
list = list.filter((t) => t.done === (done === 'true'));
}
if (q !== undefined) {
const words = String(q).toLowerCase();
list = list.filter((t) => t.title.toLowerCase().includes(words));
}
res.json(list);
});
router.get('/:id', (req, res) => {
const task = tasks.find((t) => t.id === Number(req.params.id));
if (!task) {
return sendError(res, 404, 'not_found', 'Task not found');
}
res.json(task);
});
router.post('/', (req, res) => {
const result = NewTask.safeParse(req.body);
if (!result.success) {
return sendInvalid(res, result.error);
}
const { title, done = false } = result.data;
if (titleTaken(title)) {
return sendError(res, 409, 'conflict', 'A task with this title already exists');
}
const task = { id: nextId(), title, done, createdAt: new Date().toISOString() };
tasks.push(task);
res.status(201).location(`/api/tasks/${task.id}`).json(task);
});
router.patch('/:id', (req, res) => {
const task = tasks.find((t) => t.id === Number(req.params.id));
if (!task) {
return sendError(res, 404, 'not_found', 'Task not found');
}
const result = TaskChanges.safeParse(req.body);
if (!result.success) {
return sendInvalid(res, result.error);
}
if (result.data.title !== undefined && titleTaken(result.data.title, task.id)) {
return sendError(res, 409, 'conflict', 'A task with this title already exists');
}
Object.assign(task, result.data);
res.json(task);
});
router.put('/:id', (req, res) => {
const index = tasks.findIndex((t) => t.id === Number(req.params.id));
if (index === -1) {
return sendError(res, 404, 'not_found', 'Task not found');
}
const result = Task.safeParse(req.body);
if (!result.success) {
return sendInvalid(res, result.error);
}
const { id, createdAt } = tasks[index];
if (titleTaken(result.data.title, id)) {
return sendError(res, 409, 'conflict', 'A task with this title already exists');
}
tasks[index] = { id, ...result.data, createdAt };
res.json(tasks[index]);
});
router.delete('/:id', (req, res) => {
const index = tasks.findIndex((t) => t.id === Number(req.params.id));
if (index === -1) {
return sendError(res, 404, 'not_found', 'Task not found');
}
tasks.splice(index, 1);
res.status(204).end();
});
export default router;
Toutes les leçons de API REST
1Ressources et verbes
Ressources et URLCréer avec POST4Navigateurs, versions et configuration
Qu’est-ce qu’une origineAutoriser une autre origineCORSUne page qui appelle l’APIEntraînez-vous par vous-même : Playground Express