# How to Implement GraphQL in Magento 2 for Custom APIs: A Complete Guide

> Learn to implement GraphQL in Magento 2 for custom APIs. Define schemas, build resolvers, and register your module with this comprehensive guide to efficient data fetching.

- Repository: [Alessandro Ronchi/mageres](https://github.com/aleron75/mageres)
- Tags: how-to-guide
- Published: 2026-02-24

---

**To implement GraphQL in Magento 2 for custom APIs, declare a schema in `etc/graphql/schema.graphqls`, implement resolver classes using `ResolverInterface`, register them in [`etc/di.xml`](https://github.com/aleron75/mageres/blob/main/etc/di.xml), and register your module with [`registration.php`](https://github.com/aleron75/mageres/blob/main/registration.php) and [`module.xml`](https://github.com/aleron75/mageres/blob/main/module.xml).**

Magento 2 provides a robust GraphQL server implementation that enables developers to expose custom data models through a flexible query language. When you implement GraphQL in Magento 2 for custom APIs, you leverage the platform's built-in schema validation, resolver dependency injection, and automatic endpoint generation. This guide references practical examples from the `aleron75/mageres` repository to demonstrate production-ready patterns for building scalable GraphQL APIs.

## Prerequisites for Implementing GraphQL in Magento 2

Before you begin, ensure you have a working Magento 2 installation (2.3.x or later for native GraphQL support). You should understand PHP 7.4+ or 8.x syntax, XML configuration patterns used in Magento, and the standard module structure ([`registration.php`](https://github.com/aleron75/mageres/blob/main/registration.php), [`etc/module.xml`](https://github.com/aleron75/mageres/blob/main/etc/module.xml)). Familiarity with GraphQL query syntax and type definitions is beneficial but not required.

## Step-by-Step Implementation Guide

### Step 1: Declare the GraphQL Schema

Create the file `etc/graphql/schema.graphqls` in your module directory. This file defines the **types**, **queries**, **mutations**, and **input objects** your API exposes. Magento automatically aggregates all `schema.graphqls` files across modules at runtime.

```graphql

# File: app/code/Vendor/HelloWorld/etc/graphql/schema.graphqls

type Query {
    helloWorld(message: String!): String @resolver(class: "Vendor\\HelloWorld\\GraphQl\\Resolver\\HelloWorld")
}

```

The `@resolver` directive maps the field to a specific PHP class. For complex schemas, you can also define custom types, enums, and interfaces following the GraphQL specification.

### Step 2: Create Resolver Classes

Resolvers contain the business logic for fetching or mutating data. Create a class in `GraphQl/Resolver/` that implements `\Magento\Framework\GraphQl\Query\ResolverInterface` for queries, or `\Magento\Framework\GraphQl\Query\Resolver\MutationResolverInterface` for mutations.

```php
<?php
// File: app/code/Vendor/HelloWorld/GraphQl/Resolver/HelloWorld.php
declare(strict_types=1);

namespace Vendor\HelloWorld\GraphQl\Resolver;

use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

class HelloWorld implements ResolverInterface
{
    /**
     * @inheritdoc
     */
    public function resolve(
        Field $field,
        $context,
        ResolveInfo $info,
        array $value = null,
        array $args = null
    ) {
        $message = $args['message'] ?? '';
        return strtoupper($message);
    }
}

```

The `resolve()` method receives the field configuration, execution context, parent value (for nested resolvers), and arguments. Use `$context->getUserId()` to check authentication status when implementing protected endpoints.

### Step 3: Register Resolvers in DI Configuration

While the `@resolver` directive in the schema file handles basic mapping, complex scenarios requiring constructor injection or preference overrides need explicit configuration in [`etc/di.xml`](https://github.com/aleron75/mageres/blob/main/etc/di.xml).

```xml
<?xml version="1.0"?>
<!-- File: app/code/Vendor/HelloWorld/etc/di.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Vendor\HelloWorld\GraphQl\Resolver\HelloWorld">
        <arguments>
            <argument name="logger" xsi:type="object">Psr\Log\LoggerInterface</argument>
        </arguments>
    </type>
</config>

```

According to the `aleron75/mageres` collection, the [Automatic Persisted Queries](https://github.com/danslo/magento2-module-automatic-persisted-queries) module demonstrates advanced DI configuration patterns for GraphQL extensions.

### Step 4: Register the Magento Module

Complete the module structure with standard Magento registration files.

```xml
<?xml version="1.0"?>
<!-- File: app/code/Vendor/HelloWorld/etc/module.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_HelloWorld" setup_version="1.0.0"/>
</config>

```

```php
<?php
// File: app/code/Vendor/HelloWorld/registration.php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Vendor_HelloWorld',
    __DIR__
);

```

Enable the module by running `bin/magento module:enable Vendor_HelloWorld` followed by `bin/magento setup:upgrade`.

## Architectural Flow of Magento 2 GraphQL Requests

Understanding the request lifecycle helps debug resolver issues and optimize performance. When you implement GraphQL in Magento 2 for custom APIs, the platform handles the following flow automatically:

```

Client → HTTP POST /graphql
   │
   └─► Magento GraphQL engine parses the query → looks up schema.graphqls
          │
          └─► For each field, the engine resolves by calling the class
                configured in di.xml (Resolver)
                   │
                   └─► Resolver executes business logic (models, repositories,
                         services) and returns data
                           │
                           └─► Engine assembles the response JSON

```

The **schema** serves as the contract, the **resolver** provides the implementation, and the **DI configuration** bridges them. Magento’s GraphQL stack automatically handles authentication, request validation, and caching hooks.

## Best Practices for Production GraphQL APIs

### Authentication and Authorization

Protect sensitive endpoints by adding the `@auth` directive to your schema or checking `$context->getUserId()` inside resolvers. For role-based access, verify user permissions against Magento's authorization service.

### Error Handling

Throw `\Magento\Framework\GraphQl\Exception\GraphQlInputException` for validation errors or `\Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException` for permission problems. These exceptions automatically format responses according to the GraphQL specification.

### Caching Strategy

Leverage Magento’s built-in result caching using the `@cache` directive in your schema for read-heavy operations. For schema introspection performance, the [Magento 2 GraphQL Introspection Cache](https://github.com/graycoreio/magento2-graphql-introspection-cache) module from the `aleron75/mageres` collection reduces bootstrapping overhead.

### Testing

Write integration tests extending `\Magento\TestFramework\GraphQl\Query\Resolver\ResolverTestCase` to verify resolver behavior against actual database state. Test both success paths and error conditions.

### CORS and Rate Limiting

When exposing endpoints to external Single Page Applications (SPAs), enable the [Magento 2 CORS](https://github.com/graycoreio/magento2-cors) module to handle cross-origin headers. Consider implementing rate limiting to protect against abuse.

## Summary

- **Declare your schema** in `etc/graphql/schema.graphqls` using GraphQL type definitions and the `@resolver` directive to map fields to PHP classes.
- **Implement resolvers** by creating classes that implement `ResolverInterface` or `MutationResolverInterface`, placing business logic in the `resolve()` method.
- **Configure dependency injection** in [`etc/di.xml`](https://github.com/aleron75/mageres/blob/main/etc/di.xml) when resolvers require constructor arguments or complex service dependencies.
- **Register the module** using standard Magento patterns ([`registration.php`](https://github.com/aleron75/mageres/blob/main/registration.php) and [`etc/module.xml`](https://github.com/aleron75/mageres/blob/main/etc/module.xml)) and enable it via CLI.
- **Follow production best practices** including authentication checks, proper exception handling, caching strategies, and CORS configuration when exposing APIs to external clients.

## Frequently Asked Questions

### What is the difference between REST and GraphQL APIs in Magento 2?

REST APIs in Magento 2 use fixed endpoints that return predetermined data structures, often requiring multiple requests to fetch related data. GraphQL allows clients to request exactly the fields they need in a single query, reducing over-fetching and enabling more efficient data retrieval for modern frontend applications.

### How do I handle authentication for custom GraphQL APIs?

You can protect custom GraphQL APIs by adding the `@auth` directive to fields in your `schema.graphqls` file, which requires a valid customer or admin token. Alternatively, check `$context->getUserId()` inside your resolver's `resolve()` method to verify the user identity before executing sensitive operations.

### Can I cache custom GraphQL queries in Magento 2?

Yes, you can enable caching for custom GraphQL queries by adding the `@cache` directive to your schema definitions, which stores resolver results in Magento's cache storage. For schema introspection queries, install the [GraphQL Introspection Cache](https://github.com/graycoreio/magento2-graphql-introspection-cache) module to reduce server load during schema discovery.

### Where should I place my resolver classes in the module structure?

Place resolver classes in the `GraphQl/Resolver/` directory of your module (e.g., `app/code/Vendor/Module/GraphQl/Resolver/`), following Magento's standard directory conventions. Each resolver should implement `\Magento\Framework\GraphQl\Query\ResolverInterface` for queries or `\Magento\Framework\GraphQl\Query\Resolver\MutationResolverInterface` for mutations.