Konflikte
Teil des Abschnitts REST-APIs der Node.js-Journey von Coddy. Lektion 13 von 25.
Eine zweite Aufgabe namens „Rechnung senden“ macht die Liste verwirrend, aber ihr Inhalt ist gültig. Das ist ein 409-Konflikt: Die Anfrage steht im Konflikt mit dem, was bereits gespeichert ist. Ein 400 bedeutet, dass der Inhalt selbst fehlerhaft ist.
const taken = users.some((u) => u.name.toLowerCase() === name.toLowerCase());
if (taken) {
return sendError(res, 409, 'conflict', 'That username is taken');
}Vergleiche in Kleinbuchstaben, da Menschen „Ada“ und „ada“ als denselben Namen lesen. Wenn eine Anfrage etwas umbenennt, überspringe das Element selbst bei der Suche. Andernfalls erhält ein Benutzer, der das Formular speichert, ohne seinen Namen zu ändern, einen Konflikt mit sich selbst.
Aufgabe
EinfachZwei Aufgaben mit dem Titel "Send the invoice" machen die Liste unübersichtlich. Lehne einen Titel ab, den eine andere Aufgabe bereits hat.
- Vergleiche in
routes/tasks.jsdie Titel ohne Beachtung der Groß- und Kleinschreibung: "Book the meeting room" und "book the MEETING room" gelten als derselbe Titel. - Wenn die Schema-Prüfung in POST bestanden wurde: Falls eine Aufgabe bereits diesen Titel hat, verwende
sendError, um mit Status 409 zu antworten, und füge nichts hinzu:{ "error": { "code": "conflict", "message": "A task with this title already exists" } } - Gehe in PATCH (nur wenn der Body ein
titlesendet) und in PUT genauso vor. Lass bei diesen beiden Routen die Aufgabe, die geändert wird, bei der Suche außen vor, damit eine Aufgabe ihren eigenen Titel behalten oder nur dessen Groß- und Kleinschreibung ändern kann. Ein abgelehntes PATCH oder PUT ändert nichts.
Probiere es aus: Sende POST { "title": "book the meeting room" } an /api/tasks: Du erhältst 409 mit dem Code conflict, weil Aufgabe 2 den Titel "Book the meeting room" trägt. PATCH /api/tasks/3 mit { "title": "Write the Project Brief" }: 409, und GET /api/tasks/3 zeigt weiterhin "Send the invoice". PUT /api/tasks/2 mit { "title": "Book the meeting room", "done": true }: 200, weil das der eigene Titel von Aufgabe 2 ist. Sende POST { "title": "Order new chairs" }: 201.
Probier es selbst
import { Router } from 'express';
import { z } from 'zod';
import { sendError, sendInvalid } from '../errors.js';
import { nextId, tasks } from '../store.js';
const router = Router();
// Eine vollständige Aufgabe, wie sie von PUT gesendet wird. .strict() lehnt Felder ab, die nicht aufgeführt sind.
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();
router.get('/', (req, res) => {
res.json(tasks);
});
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;
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);
}
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];
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;
Alle Lektionen in REST-APIs
1Ressourcen und Verben
Ressourcen und URLsErstellen mit POST4Browser, Versionen und Konfiguration
Was ist ein Origin?Einen anderen Origin zulassenCORSEine Seite, die die API aufruftÜbe selbstständig: Express-Playground