Menu
CoddyTech

Konflik

Termasuk bagian REST API dalam perjalanan Node.js di Coddy. Pelajaran 9 dari 18.

Tugas kedua bernama "Send the invoice" membuat daftar membingungkan, tetapi isinya valid. Itu adalah 409 Conflict: permintaan bertentangan dengan yang sudah tersimpan. Kode 400 berarti isi permintaannya sendiri salah.

const taken = users.some((u) => u.name.toLowerCase() === name.toLowerCase());
if (taken) {
    return sendError(res, 409, 'conflict', 'That username is taken');
}

Bandingkan dalam huruf kecil, karena orang membaca "Ada" dan "ada" sebagai nama yang sama. Saat permintaan mengganti nama sesuatu, lewati item itu sendiri dalam pencarian. Jika tidak, pengguna yang menyimpan formulir tanpa mengubah namanya akan mengalami konflik dengan dirinya sendiri.

challenge icon

Tantangan

Mudah
  • Judul yang sudah dimiliki tugas lain, tanpa membedakan huruf besar dan kecil, menghasilkan respons 409 dengan kode conflict: pada POST, serta pada PATCH dan PUT saat menetapkan judul.
  • Tugas boleh tetap menggunakan judulnya sendiri.

Kirim POST dengan { "title": "book the meeting room" }, lalu PUT /api/tasks/2 dengan { "title": "Book the meeting room", "done": true }.

Coba sendiri

import { Router } from 'express';
import { z } from 'zod';
import { sendError, sendInvalid } from '../errors.js';
import { nextId, tasks } from '../store.js';

const router = Router();

// Task lengkap, seperti yang dikirim oleh PUT. .strict() menolak field yang tidak tercantum di dalamnya.
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;

Semua pelajaran di REST API

Latihan sendiri: Playground Express