Skip to content

Gestion de liste de souhaits

Guide d'implémentation d'une liste de souhaits avec priorité et notes. Couvre le pattern d'existence non-divulguée, l'ajout idempotent et les paramètres de chemin multiples.

Vue d'ensemble

  • Les utilisateurs créent des listes de souhaits nommées (publiques/privées)
  • Chaque liste de souhaits peut contenir des produits (priority : high/medium/low, note optionnelle)
  • Les listes de souhaits privées retournent 404 aux non-propriétaires (pattern d'existence non-divulguée)
  • L'ajout de produit est idempotent (200 si existant, 201 si nouveau)
  • Pas d'ordre (pas de gestion de position) — principale différence avec la collection de contenu (FT149)

Endpoints

MéthodeCheminDescription
POST/wishlistsCréer une liste de souhaits
GET/wishlists/{id}Obtenir une liste de souhaits (publique ou la sienne)
PUT/wishlists/{id}Modifier le nom et la visibilité
DELETE/wishlists/{id}Supprimer la liste de souhaits
POST/wishlists/{id}/itemsAjouter un produit (idempotent)
DELETE/wishlists/{id}/items/{productId}Supprimer un produit

Conception de la base de données

sql
CREATE TABLE wishlists (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    name TEXT NOT NULL,
    is_public INTEGER NOT NULL DEFAULT 0,
    created_at TEXT NOT NULL,
    updated_at TEXT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE wishlist_items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    wishlist_id INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    priority TEXT NOT NULL DEFAULT 'medium',
    note TEXT,
    added_at TEXT NOT NULL,
    UNIQUE (wishlist_id, product_id),
    CHECK (priority IN ('high', 'medium', 'low')),
    FOREIGN KEY (wishlist_id) REFERENCES wishlists(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

Contrairement à la collection de contenu (FT149), il n'y a pas de colonne position. UNIQUE (wishlist_id, product_id) est la défense au niveau DB pour l'ajout idempotent.

Pattern d'existence non-divulguée

php
$isOwner = $actorId !== null && (int) $wishlist['user_id'] === $actorId;
$isPublic = (bool) $wishlist['is_public'];

if (!$isOwner && !$isPublic) {
    return $this->responseFactory->create(['error' => 'wishlist not found'], 404);
}

Seul GET retourne 404. PUT/DELETE/POST items retournent 403 pour informer le propriétaire d'une autorisation insuffisante.

Ajout idempotent d'article

php
$existing = $this->repository->findItem($id, $productId);
if ($existing !== null) {
    return $this->responseFactory->create([
        'message' => 'already in wishlist',
        'product_id' => $productId,
        'priority' => $existing['priority'],
        'note' => $existing['note'],
    ], 200);
}
$now = date('c');
$this->repository->addItem($id, $productId, $priority, $note, $now);
return $this->responseFactory->create([...], 201);

Validation de la priorité (repli vers la valeur par défaut pour les valeurs invalides)

php
private const array VALID_PRIORITIES = ['high', 'medium', 'low'];

$priority = isset($body['priority']) && is_string($body['priority'])
    && in_array($body['priority'], self::VALID_PRIORITIES, true)
    ? $body['priority']
    : 'medium';

Les valeurs de priorité invalides se replient sur 'medium' au lieu de retourner une erreur. Cela permet aux clients de gérer en toute sécurité les valeurs de priorité inconnues pour la compatibilité ascendante.

Exemple de réponse GET /wishlists/

json
{
  "id": 1,
  "user_id": 1,
  "name": "Birthday Wishlist",
  "is_public": true,
  "item_count": 2,
  "items": [
    {
      "product_id": 3,
      "product_name": "Wireless Headphones",
      "priority": "high",
      "note": "Black color preferred",
      "added_at": "2026-05-21T..."
    },
    {
      "product_id": 1,
      "product_name": "Coffee Mug",
      "priority": "low",
      "note": null,
      "added_at": "2026-05-21T..."
    }
  ],
  "created_at": "2026-05-21T...",
  "updated_at": "2026-05-21T..."
}

Différences entre collection et liste de souhaits

AspectCollection (FT149)Liste de souhaits (FT151)
OrdreGestion de positionAucun (ordre d'ajout)
Métadonnées d'articleAucunepriority + note
Limite50 articlesAucune
Cas d'usageListe de lecture, curationListe d'envies, registre de cadeaux

Pattern de vérification de propriété

php
if ((int) $wishlist['user_id'] !== $actorId) {
    return $this->responseFactory->create(['error' => 'access denied'], 403);
}

Le même pattern est utilisé pour PUT/DELETE/POST items.

Publié sous licence MIT.