Building MIRROR: A Luxury AI Fashion Try-On App with Perfect Corp APIs

Published: (March 6, 2026 at 11:31 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

What Is MIRROR?

MIRROR is a full‑stack web app that combines a high‑end product‑browsing experience with AI‑powered virtual try‑on.

  • A user browses products.
  • Opens a try‑on modal, uploads a photo, and sees an AI‑generated preview of themselves wearing the item.
  • Adds the item to the cart – all without leaving the page.

The app supports four product categories, each with its own Perfect Corp endpoint and payload structure:

  • Clothing
  • Shoes
  • Bags
  • Earrings

MIRROR Home page (Photo by Cottonbro Studio)

Tech Stack

LayerTechnologies
FrontendReact, React Router, Context API, custom CSS (no UI framework)
BackendNode.js + Express
AIPerfect Corp S2S (Server‑to‑Server) APIs
Photo persistencelocalStorage (up to 10 saved user photos)
CartlocalStorage with quantity aggregation

Architecture

The key architectural decision was to keep the frontend completely decoupled from Perfect Corp. The React app never calls Perfect Corp directly; all AI requests go through the Express backend.

Client (React) → POST /api/tryon → Express Server → Perfect Corp S2S API

Perfect Corp’s APIs require publicly accessible URLs for both the user photo and the product reference image. The server therefore:

  1. Saves the uploaded user photo to disk.
  2. Constructs a public URL (via ngrok in development).

Dynamic Endpoint Routing by Product Type

Perfect Corp uses a different endpoint for each product category, each expecting a distinct payload shape. I solved this with a clean switch‑based config lookup:

function getPerfectConfig(productType) {
  switch (String(productType || "").toLowerCase()) {
    case "cloth":
      return {
        startUrl: "https://yce-api-01.makeupar.com/s2s/v2.0/task/cloth",
        /* …other config… */
      };
    case "earrings":
      return {
        startUrl:
          "https://yce-api-01.makeupar.com/s2s/v2.0/task/2d-vto/earring",
        /* …other config… */
      };
    case "shoes":
      return {
        startUrl: "https://yce-api-01.makeupar.com/s2s/v2.0/task/shoes",
        /* …other config… */
      };
    case "bag":
      return {
        startUrl: "https://yce-api-01.makeupar.com/s2s/v2.0/task/bag",
        /* …other config… */
      };
    default:
      throw new Error(`Unsupported product type: ${productType}`);
  }
}

buildPayload() then creates the correct request body for each type:

  • Clothing – needs garment_category and change_shoes.
  • Shoes / Bags – require a gender field.
  • Earrings – the most complex: need ref_file_urls (array), source_info, and object_infos.

MIRROR Item page (Photo by Cottonbro Studio)

Task‑Polling Pattern

Perfect Corp’s API is asynchronous:

  1. POST → start a task → receive task_id.
  2. GET → poll /task/{task_id} until task_status === "success".

I built a reusable poller:

async function pollPerfect({
  pollBaseUrl,
  token,
  taskId,
  intervalMs = 2000,
  maxAttempts = 120,
}) {
  const headers = { Authorization: `Bearer ${token}` };

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetch(`${pollBaseUrl}/task/${taskId}`, { headers });
    const data = await res.json();

    if (data.task_status === "success") return data;
    if (data.task_status === "failed") throw new Error("Task failed");

    await new Promise((r) => setTimeout(r, intervalMs));
  }
  throw new Error("Polling timed out");
}

Local Development Setup

# Set env var for public URL (ngrok)
echo "PUBLIC_BASE_URL=https://your-ngrok-url.ngrok.app" >> server/.env

# Expose server (Perfect Corp needs a public URL)
ngrok http 5000

# Start backend + frontend
node server/index.js
cd client && npm start

Wrapping Up

MIRROR was a great way to explore AI‑powered fashion tech in a hackathon format. The most interesting engineering challenge was juggling the different API contracts for each product category while keeping the frontend interface clean and consistent.

If you’re looking to integrate Perfect Corp’s virtual try‑on APIs, the biggest thing to know upfront is the public URL requirement. Plan your image‑hosting strategy before you start as well, and you’ll save yourself a lot of debugging.

The full source is on GitHub – feel free to take a look or use it as a reference for your own try‑on projects.

View the repo here

0 views
Back to Blog

Related posts

Read more »