Sylius13 min

Sylius Shop API : integrer un frontend headless avec React ou Next.js

Par Pierre-Arthur Demengel
SyliusShop APIHeadlessReactNext.js

Le headless commerce separe le frontend du backend. Sylius devient un moteur API pur, et vous construisez l'interface avec la technologie de votre choix : React, Next.js, Vue, Nuxt, ou meme une app mobile. Voici comment structurer cette architecture.

Architecture cible

                    CDN (Vercel / Cloudflare)
                           |
                    Next.js Frontend
                    (SSR / ISR / CSR)
                           |
                    HTTPS + JWT
                           |
                    Sylius Backend
                    (API Platform)
                           |
                    PostgreSQL + Redis

Configuration CORS sur Sylius

Installez et configurez NelmioCorsBundle :

composer require nelmio/cors-bundle

# config/packages/nelmio_cors.yaml
nelmio_cors:
  defaults:
    origin_regex: true
    allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
    allow_methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']
    allow_headers: ['Content-Type', 'Authorization']
    max_age: 3600
  paths:
    '^/api/':
      allow_origin: ['https://www.votre-front.com']

Client API cote React

Creez un client API type :

// lib/sylius-client.ts
const API_URL = process.env.NEXT_PUBLIC_SYLIUS_API_URL;

class SyliusClient {
  private token: string | null = null;

  async authenticate(email: string, password: string) {
    const res = await fetch(`${API_URL}/shop/authentication-token`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password }),
    });
    const data = await res.json();
    this.token = data.token;
    return data;
  }

  async get(endpoint: string) {
    const headers: Record<string, string> = {
      'Accept': 'application/ld+json',
    };
    if (this.token) headers['Authorization'] = `Bearer ${this.token}`;

    const res = await fetch(`${API_URL}${endpoint}`, { headers });
    if (!res.ok) throw new Error(`API error: ${res.status}`);
    return res.json();
  }

  async getProducts(page = 1, perPage = 12) {
    return this.get(`/shop/products?page=${page}&itemsPerPage=${perPage}`);
  }

  async getProduct(code: string) {
    return this.get(`/shop/products/${code}`);
  }

  async getCart(token: string) {
    return this.get(`/shop/orders/${token}`);
  }
}

export const sylius = new SyliusClient();

Pages produits avec Next.js ISR

// app/products/[code]/page.tsx
import { sylius } from '@/lib/sylius-client';

export async function generateStaticParams() {
  const products = await sylius.getProducts(1, 100);
  return products['hydra:member'].map((p: any) => ({
    code: p.code,
  }));
}

export const revalidate = 3600; // Regenerer toutes les heures

export default async function ProductPage({
  params
}: {
  params: { code: string }
}) {
  const product = await sylius.getProduct(params.code);

  return (
    <main className="max-w-6xl mx-auto px-4 py-8">
      <h1 className="text-3xl font-bold">{product.name}</h1>
      <p>{product.shortDescription}</p>
      {/* Galerie, variantes, ajout panier... */}
    </main>
  );
}

Gestion du panier

Le panier Sylius est identifie par un token unique. Stockez-le dans un cookie ou localStorage :

// hooks/useCart.ts
import { useState, useEffect } from 'react';
import { sylius } from '@/lib/sylius-client';

export function useCart() {
  const [cartToken, setCartToken] = useState<string | null>(null);
  const [cart, setCart] = useState(null);

  async function createCart() {
    const res = await fetch(`${API_URL}/shop/orders`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ localeCode: 'fr_FR' }),
    });
    const data = await res.json();
    setCartToken(data.tokenValue);
    localStorage.setItem('cart_token', data.tokenValue);
    return data;
  }

  async function addItem(variantCode: string, quantity: number) {
    let token = cartToken;
    if (!token) {
      const newCart = await createCart();
      token = newCart.tokenValue;
    }
    // POST item to cart...
  }

  return { cart, addItem, cartToken };
}

Quand choisir le headless

  • Oui : trafic eleve (100K+ visites/mois), equipe front JS confirmee, multi-canal (web + app mobile), besoin de performances extremes
  • Non : budget limite, equipe back-end uniquement, projet simple, time-to-market court

Le headless n'est pas une fin en soi. C'est un choix d'architecture qui se justifie par des besoins concrets. Pour la majorite des projets Sylius, le theming classique suffit.

Besoin d'accompagnement pour votre projet headless ? Parlons-en. Voir aussi notre article sur l'API Platform de Sylius.

Questions fréquentes

13 projets livrésGrand-Est & BelgiqueLighthouse >90Disponible immédiatement

Un projet en tête ?

Discutons de votre site web. Réponse garantie sous 24h.

Ou appelez directement :06 95 41 30 25

WhatsApp
Appeler