Magento 2 GraphQL API : Guide du développeur complet (2026)
L’API GraphQL de Magento 2 est le pilier des vitrines headless modernes, des PWA et des applications mobiles. Contrairement à REST — qui nécessite souvent plusieurs allers-retours — GraphQL permet à un client de demander exactement les champs dont il a besoin en un seul appel. Ce guide couvre le schéma intégré, l’authentification, les mutations de panier et de checkout, le développement de résolveurs personnalisés et les modèles de performance qui comptent en production.
En résumé : GraphQL dans Magento 2 expose les produits, catégories, panier, checkout et données clients via un schéma typé à
/graphql. Utilisez les queries pour la lecture, les mutations pour l’écriture, et étendez le schéma avec des résolveurs personnalisés lorsque les champs intégrés ne suffisent pas.
Table des matières
- Pourquoi GraphQL pour Magento 2 ?
- Endpoint, en-têtes et première requête
- Schéma de base : produits, catégories, recherche
- Mutations de panier et checkout
- Authentification client
- Construction d’un résolveur de requête personnalisé
- Construction d’une mutation personnalisée
- Performance et mise en cache
- GraphQL vs REST : quand utiliser quoi
- FAQ technique
Pourquoi GraphQL pour Magento 2 ?
Adobe a massivement investi dans GraphQL comme API principale pour les opérations côté vitrine. REST reste disponible pour les intégrations Admin et les systèmes legacy, mais les nouveaux travaux frontend — Hyvä React Checkout, PWA Studio, vitrines Next.js personnalisées — fonctionnent sur GraphQL.
| Avantage | Détail |
|---|---|
| Requête unique | Récupérez nom, prix, image et stock d’un produit en un appel |
| Pas de sur-récupération | Le client sélectionne uniquement les champs qu’il affiche |
| Schéma typé | Auto-documenté via l’introspection |
| État du panier | Le modèle de token cart_id convient aux frontends sans état |
| Stabilité des versions | Le schéma évolue avec des dépréciations rétrocompatibles |
Endpoint :
POST https://your-store.com/graphql
Content-Type: application/json
Endpoint, en-têtes et première requête
Requête de produit de base
{
products(filter: { sku: { eq: "24-MB01" } }) {
items {
sku
name
price_range {
minimum_price {
regular_price {
value
currency
}
}
}
image {
url
label
}
}
}
}
Envoyez-la avec curl :
curl -X POST https://your-store.com/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ products(filter: { sku: { eq: \"24-MB01\" } }) { items { sku name } } }"}'
En-tête Store (configurations multi-boutiques)
Lorsque vous utilisez plusieurs vues de boutique, passez l’en-tête Store :
-H "Store: default"
Sans cela, Magento peut renvoyer des données de la mauvaise vue de boutique — mauvais prix, mauvaise langue, mauvaise devise.
Schéma de base : produits, catégories, recherche
Liste des catégories avec filtres
{
categoryList(filters: { url_key: { eq: "gear" } }) {
id
name
products(pageSize: 12, currentPage: 1) {
total_count
items {
sku
name
small_image { url }
price_range {
minimum_price {
final_price { value currency }
}
}
}
page_info {
current_page
total_pages
}
}
}
}
Recherche en texte intégral
{
products(search: "backpack", pageSize: 10) {
total_count
items {
sku
name
url_key
}
}
}
La recherche repose sur l’indexeur catalogsearch_fulltext et Elasticsearch/OpenSearch. Si la recherche ne renvoie aucun résultat, réindexez d’abord :
bin/magento indexer:reindex catalogsearch_fulltext
Options de produit configurable
{
products(filter: { sku: { eq: "MH01" } }) {
items {
sku
name
... on ConfigurableProduct {
configurable_options {
attribute_code
label
values {
value_index
label
}
}
variants {
product {
sku
name
price_range {
minimum_price {
final_price { value }
}
}
}
}
}
}
}
}
Utilisez les fragments inline (... on ConfigurableProduct) pour accéder aux champs spécifiques au type — un modèle GraphQL de base dans Magento.
Mutations de panier et checkout
Les paniers invités utilisent un cart_id (identifiant de devis masqué). Les paniers clients utilisent le token client authentifié.
Créer un panier invité
mutation {
createEmptyCart
}
Réponse :
{ "data": { "createEmptyCart": "abc123xyz" } }
Ajouter un produit au panier
mutation {
addProductsToCart(
cartId: "abc123xyz"
cartItems: [{ sku: "24-MB01", quantity: 1 }]
) {
cart {
items {
quantity
product {
name
sku
}
}
prices {
grand_total {
value
currency
}
}
}
}
}
Fusionner le panier invité après connexion
mutation {
mergeCarts(
source_cart_id: "abc123xyz"
destination_cart_id: "customer-cart-id"
) {
items { quantity product { sku } }
}
}
Définir l’adresse de livraison et le mode d’expédition
mutation {
setShippingAddressesOnCart(
input: {
cart_id: "abc123xyz"
shipping_addresses: [{
address: {
firstname: "John"
lastname: "Doe"
street: ["123 Main St"]
city: "Paris"
postcode: "75001"
country_code: FR
telephone: "0600000000"
}
}]
}
) {
cart {
shipping_addresses {
available_shipping_methods {
carrier_code
method_code
amount { value currency }
}
}
}
}
}
Astuce checkout headless : Demandez toujours
available_shipping_methodsetavailable_payment_methodsaprès avoir défini l’adresse — les tarifs dépendent du contenu du panier et de la destination.
Authentification client
Générer un token client
mutation {
generateCustomerToken(
email: "[email protected]"
password: "Password123!"
) {
token
}
}
Utilisez le token dans les requêtes suivantes :
-H "Authorization: Bearer <token>"
Les tokens expirent selon la configuration Admin (Stores → Configuration → Services → OAuth → Customer Token Lifetime). La valeur par défaut est 1 heure — planifiez la logique de rafraîchissement dans votre frontend.
Requête d’introspection (dev uniquement)
Désactivez l’introspection en production pour des raisons de sécurité. En développement, explorez le schéma :
{
__schema {
types {
name
kind
}
}
}
Ou utilisez GraphQL Playground / Altair / Postman avec l’introspection activée.
Construction d’un résolveur de requête personnalisé
Lorsque le schéma intégré ne suffit pas, étendez-le avec un module personnalisé.
Structure du répertoire
app/code/MagentoMastery/GraphQlDemo/
├── registration.php
├── etc/
│ ├── module.xml
│ └── schema.graphqls
└── Model/
└── Resolver/
└── HelloWorld.php
Query schema.graphqls
type Query {
helloWorld(name: String): String
@resolver(class: "MagentoMastery\\GraphQlDemo\\Model\\Resolver\\HelloWorld")
@doc(description: "Returns a greeting string")
}
Classe résolveur
<?php
declare(strict_types=1);
namespace MagentoMastery\GraphQlDemo\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
class HelloWorld implements ResolverInterface
{
public function resolve(
Field $field,
$context,
ResolveInfo $info,
?array $value = null,
?array $args = null
): string {
$name = $args['name'] ?? 'World';
return "Hello, {$name}!";
}
}
Tester la requête personnalisée
{ helloWorld(name: "Magento") }
Après le déploiement :
bin/magento setup:upgrade
bin/magento cache:flush
Les modifications du schéma GraphQL nécessitent une vidange du cache — Magento met en cache le schéma compilé.
Construction d’une mutation personnalisée
Les mutations suivent le même modèle mais implémentent ResolverInterface sur un champ de type Mutation.
Mutation schema.graphqls
type Mutation {
subscribeNewsletter(email: String!): NewsletterOutput
@resolver(class: "MagentoMastery\\GraphQlDemo\\Model\\Resolver\\SubscribeNewsletter")
}
type NewsletterOutput {
success: Boolean!
message: String
}
Résolveur avec validation
<?php
declare(strict_types=1);
namespace MagentoMastery\GraphQlDemo\Model\Resolver;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
class SubscribeNewsletter implements ResolverInterface
{
public function resolve(
Field $field,
$context,
ResolveInfo $info,
?array $value = null,
?array $args = null
): array {
$email = $args['email'] ?? '';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new GraphQlInputException(__('Adresse e-mail invalide.'));
}
// Subscribe logic here...
return [
'success' => true,
'message' => 'Subscribed successfully.',
];
}
}
Lancez GraphQlInputException pour les erreurs client (niveau 400) et GraphQlAuthorizationException pour les échecs d’authentification — Magento les traduit en réponses d’erreur GraphQL appropriées.
Performance et mise en cache
GraphQL peut être plus lent que prévu si les clients demandent trop de champs imbriqués. Appliquez ces règles en production :
1. Limiter la profondeur et la complexité des requêtes
Utilisez un proxy inverse ou les limites de complexité de requêtes intégrées de Magento (Adobe Commerce) pour bloquer les requêtes abusives.
2. Mettre en cache au CDN pour les requêtes anonymes
Ne mettez en cache que les requêtes qui n’incluent pas de tokens client ou d’ID de panier. Les requêtes de liste de produits sont de bons candidats CDN lorsqu’elles sont indexées par boutique + hash de requête.
3. Éviter le N+1 dans les résolveurs personnalisés
Lors de la résolution de listes, utilisez des résolveurs par lots ou des data loaders. Un résolveur naïf qui charge un modèle de produit par élément détruira les performances sur les pages de catégories.
4. Ne demander que ce que vous affichez
items { sku name description { html } }
items { sku name small_image { url } price_range { minimum_price { final_price { value } } } }
5. Maintenir les indexeurs à jour
GraphQL lit à partir de tables plates indexées et d’Elasticsearch. Des indexeurs obsolètes = des réponses API obsolètes. Consultez le guide des indexeurs pour la maintenance.
GraphQL vs REST : quand utiliser quoi
| Cas d’utilisation | API recommandée |
|---|---|
| Vitrine / PWA / application mobile | GraphQL |
| Intégrations admin (commandes, import catalogue) | REST (Async Bulk API) |
| Synchronisation ERP tierce | REST |
| Panier/checkout en temps réel | GraphQL |
| Intégrations legacy | REST |
La direction d’Adobe est claire : GraphQL pour le face-client, REST pour les opérations groupées opérationnelles/back-office.
FAQ technique
Où est défini le schéma GraphQL ?
Les fichiers de schéma de base vivent dans etc/schema.graphqls de chaque module. Magento les fusionne à l’exécution. Les modules personnalisés ajoutent leur propre etc/schema.graphqls.
Puis-je utiliser GraphQL dans l’Admin ?
GraphQL est conçu pour les opérations de vitrine. Les fonctionnalités Admin utilisent REST ou l’interface Admin — n’exposez pas les opérations Admin via GraphQL personnalisé sans contrôles ACL stricts.
Comment déboguer les erreurs GraphQL ?
Activez le mode développeur et vérifiez var/log/exception.log. GraphQL renvoie les erreurs dans le tableau errors de la réponse JSON avec les champs message et category.
GraphQL remplace-t-il le checkout Knockout.js ?
Pas automatiquement. Le checkout Luma est toujours basé sur Knockout. Le checkout headless nécessite un frontend qui consomme les mutations GraphQL (React, Vue, Hyvä Checkout, etc.). Consultez le guide checkout pour travailler avec Knockout.js ou construire une alternative headless.
GraphQL est-il disponible dans Magento Open Source ?
Oui. GraphQL fait partie de Magento Open Source depuis 2.3.x. Certaines fonctionnalités avancées (limites de complexité des requêtes, aperçus de staging) sont réservées à Adobe Commerce.
Conclusion
GraphQL est la couche API standard pour les vitrines Magento 2 modernes. Maîtrisez d’abord le schéma intégré des produits et du panier, puis étendez-le avec des résolveurs personnalisés lorsque la logique métier l’exige. Gardez les requêtes légères, les indexeurs à jour et les tokens d’authentification frais — et votre vitrine headless restera rapide et fiable.
Vous construisez une vitrine headless Magento 2 ou avez besoin d’endpoints GraphQL personnalisés ? Contactez-moi pour des revues d’architecture, des modules personnalisés et de l’optimisation des performances.