My App
Wishlist

Add to Wishlist

Save a product to the user's wishlist

Overview

Add a product to the user's wishlist for future reference. This endpoint supports both authenticated and guest users with automatic session management.

Endpoint

POST /v1/wishlist

Authentication

Requires the x-api-key header for authentication.

Request

Headers

HeaderTypeRequiredDescription
x-api-keystringYesYour API authentication key

Request Body

FieldTypeRequiredDescription
productIdstringYesThe ID of the product to add

Example Request

async function addToWishlist(productId) {
  const response = await fetch('https://api.yourstore.com/v1/wishlist', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.BACKEND_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ productId })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || 'Failed to add to wishlist');
  }

  const guestToken = response.headers.get('x-guest-token');
  if (guestToken) {
    localStorage.setItem('guest_token', guestToken);
  }

  return response.json();
}

// Usage
addToWishlist('prod_123')
  .then(wishlist => console.log('Added to wishlist:', wishlist))
  .catch(error => console.error(error));
interface AddToWishlistRequest {
  productId: string;
}

interface WishlistItem {
  id: string;
  productId: string;
  product: {
    name: string;
    price: number;
    image: string;
  };
}

async function addToWishlist(
  productId: string
): Promise<WishlistItem[]> {
  const response = await fetch('https://api.yourstore.com/v1/wishlist', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.BACKEND_API_KEY!,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ 
      productId 
    } as AddToWishlistRequest)
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || 'Failed to add to wishlist');
  }

  const guestToken = response.headers.get('x-guest-token');
  if (guestToken) {
    localStorage.setItem('guest_token', guestToken);
  }

  return response.json();
}

Server Action Example (Next.js)

'use server';

import { cookieManager } from '@/lib/auth-tools';
import { revalidatePath } from 'next/cache';

export async function addToWishlistAction(productId) {
  try {
    const headers = await cookieManager.buildApiHeaders();
    
    const response = await fetch('https://api.yourstore.com/v1/wishlist', {
      method: 'POST',
      headers,
      body: JSON.stringify({ productId })
    });

    if (!response.ok) {
      const error = await response.json();
      return { 
        success: false, 
        message: error.message 
      };
    }

    await cookieManager.handleApiResponse(response);
    const wishlist = await response.json();
    
    revalidatePath('/wishlist');
    
    return { 
      success: true, 
      wishlist 
    };
  } catch (error) {
    return { 
      success: false, 
      message: 'Failed to add to wishlist' 
    };
  }
}
'use server';

import { cookieManager } from '@/lib/auth-tools';
import { revalidatePath } from 'next/cache';

interface AddToWishlistResult {
  success: boolean;
  wishlist?: any[];
  message?: string;
}

export async function addToWishlistAction(
  productId: string
): Promise<AddToWishlistResult> {
  try {
    const headers = await cookieManager.buildApiHeaders();
    
    const response = await fetch('https://api.yourstore.com/v1/wishlist', {
      method: 'POST',
      headers,
      body: JSON.stringify({ productId })
    });

    if (!response.ok) {
      const error = await response.json();
      return { 
        success: false, 
        message: error.message 
      };
    }

    await cookieManager.handleApiResponse(response);
    const wishlist = await response.json();
    
    revalidatePath('/wishlist');
    
    return { 
      success: true, 
      wishlist 
    };
  } catch (error) {
    return { 
      success: false, 
      message: 'Failed to add to wishlist' 
    };
  }
}

Wishlist Button Component

'use client';

import { addToWishlistAction } from '@/actions/wishlist';
import { useState } from 'react';
import { Heart } from 'lucide-react';

export function WishlistButton({ productId, isInWishlist = false }) {
  const [loading, setLoading] = useState(false);
  const [saved, setSaved] = useState(isInWishlist);

  const handleToggle = async () => {
    setLoading(true);
    
    const result = await addToWishlistAction(productId);
    
    if (result.success) {
      setSaved(true);
      alert('Added to wishlist!');
    } else {
      alert(result.message);
    }
    
    setLoading(false);
  };

  return (
    <button
      onClick={handleToggle}
      disabled={loading || saved}
      className={`flex items-center gap-2 px-4 py-2 rounded ${
        saved ? 'bg-red-100 text-red-600' : 'bg-gray-100'
      }`}
    >
      <Heart className={saved ? 'fill-current' : ''} size={20} />
      {saved ? 'Saved' : 'Save'}
    </button>
  );
}

Response

Success Response (200)

Returns the updated wishlist items array.

[
  {
    "id": "wish_123",
    "productId": "prod_456",
    "product": {
      "id": "prod_456",
      "name": "Wireless Headphones",
      "price": 199.99,
      "image": "https://example.com/images/headphones.jpg",
      "inStock": true
    },
    "createdAt": "2024-03-15T10:30:00Z"
  }
]

Error Responses

Status CodeDescription
401Invalid or missing API key
404Product not found
409Product already in wishlist
422Invalid input data
500Failed to add to wishlist

Important Notes

Duplicate Prevention: If a product is already in the wishlist, you'll receive a 409 error. Consider checking the wishlist state before attempting to add.

Product Validation: The API validates that the product exists and is available before adding to wishlist.

Toggle Wishlist Component

Here's a reusable component that handles both adding and removing:

'use client';

import { addToWishlistAction, removeFromWishlistAction } from '@/actions/wishlist';
import { useState } from 'react';
import { Heart } from 'lucide-react';

export function WishlistToggle({ productId, wishlistItemId = null }) {
  const [loading, setLoading] = useState(false);
  const [itemId, setItemId] = useState(wishlistItemId);

  const handleToggle = async () => {
    setLoading(true);

    if (itemId) {
      // Remove from wishlist
      const result = await removeFromWishlistAction(itemId);
      if (result.success) {
        setItemId(null);
      }
    } else {
      // Add to wishlist
      const result = await addToWishlistAction(productId);
      if (result.success && result.wishlist) {
        const newItem = result.wishlist.find(
          item => item.productId === productId
        );
        setItemId(newItem?.id);
      }
    }

    setLoading(false);
  };

  return (
    <button
      onClick={handleToggle}
      disabled={loading}
      className="p-2 rounded-full hover:bg-gray-100"
      aria-label={itemId ? 'Remove from wishlist' : 'Add to wishlist'}
    >
      <Heart 
        className={itemId ? 'fill-red-500 text-red-500' : 'text-gray-400'} 
        size={24} 
      />
    </button>
  );
}