Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Emmanuel-Mtz-777/TechStore-Explorer/llms.txt

Use this file to discover all available pages before exploring further.

The wishlist gives authenticated users a personal space to save products from the catalog for later. Every time a product is added or removed, TechStore Explorer enqueues a confirmation email to the user’s registered address so they always have a record of their changes.

How it works

1

Adding a product

A POST request to /wishlist/add (web) or POST /api/wishlist (API) triggers WishlistController@addWishlist. The controller validates the incoming product_id, then fetches the full product details from the Platzi Fake Store API (with a timeout of 8 seconds and up to 2 retries). Once the product data is confirmed, it writes a new row to the wishlists table and queues a WishlistAddedMail to the user’s address.
2

Removing a product

A DELETE request to /wishlist/remove (web) or DELETE /api/wishlist (API) triggers WishlistController@removeWishlist. It deletes the matching row identified by the authenticated user’s ID and the supplied product_id, then queues a WishlistDeletedMail.

Email notifications

Both mail classes implement ShouldQueue, meaning they are placed onto the application queue rather than sent synchronously during the HTTP request. This keeps response times fast even if the mail server is temporarily slow.
EventMailableSubject
Product added to wishlistWishlistAddedMailProducto añadido a favoritos
Product removed from wishlistWishlistDeletedMailProducto Eliminado de favoritos
Both emails are sent to auth()->user()->email. Mail dispatch errors are caught and logged (via Log::error) so a mail failure never surfaces as an HTTP error to the end user.

Wishlist data model

When a product is saved, TechStore Explorer denormalises the relevant product and category fields from the Platzi Fake Store API response directly into the wishlists row. This means wishlist data remains readable even if the external API is temporarily unavailable.
ColumnTypeDescription
user_idforeignIdOwning user (cascades on delete)
product_idstringProduct ID from the external API
product_namestringProduct title at time of saving
product_imagestringFirst image URL from the API
product_pricedecimal(8,2)Product price at time of saving
category_idstringCategory ID from the external API
category_namestringCategory name at time of saving

Web routes

All wishlist routes require the auth and verified middleware — users must be logged in and have confirmed their email address.
MethodPathController actionName
GET/wishlistWishlistController@indexwishlist
POST/wishlist/addWishlistController@addWishlistwishlist.store
DELETE/wishlist/removeWishlistController@removeWishlistwishlist.destroy

addWishlist — error handling and retry logic

The controller handles both API-level errors (product not found, API unreachable) and mail dispatch failures independently, so a problem with one does not affect the other.
public function addWishlist(Request $request)
{
    $request->validate([
        'product_id' => ['required', 'integer'],
    ]);

    try {
        $response = Http::timeout(8)
            ->retry(2, 200)
            ->get("https://api.escuelajs.co/api/v1/products/{$request->product_id}");

        if ($response->notFound()) {
            return back()->with('error', 'Producto no encontrado.');
        }

        if ($response->failed()) {
            return back()->with('error', 'Error al consultar la API.');
        }

        $product = $response->json();

        Wishlist::create([
            'user_id'        => auth()->id(),
            'product_id'     => $product['id'],
            'product_name'   => $product['title'],
            'product_image'  => $product['images'][0] ?? null,
            'product_price'  => $product['price'],
            'category_id'    => $product['category']['id'] ?? null,
            'category_name'  => $product['category']['name'] ?? null,
        ]);

        try {
            Mail::to(auth()->user()->email)
                ->queue(new WishlistAddedMail($product));
        } catch (\Throwable $e) {
            Log::error('Error enviando correo de wishlist: ' . $e->getMessage());
        }

        return back()->with(
            'success',
            'El producto se añadió correctamente. Revisa tu correo de confirmación.'
        );

    } catch (\Throwable $e) {
        Log::error('Error al consultar la API: ' . $e->getMessage());

        return back()->with(
            'error',
            'No fue posible conectar con el servicio de productos. Intenta nuevamente.'
        );
    }
}
Email delivery requires the Laravel queue worker to be running. Without it, queued mailables will never be dispatched. Start the worker with:
php artisan queue:work

Build docs developers (and LLMs) love