Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

API Documentation: REST Swagger and GraphQL Schema Introspection

API Documentation: REST Swagger and GraphQL Schema Introspection

~6 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026

Block 10 built six access points (chapters 80-83) and hardened them against abuse in chapter 86. One practical question remains: how does a partner system or a mobile app find these endpoints without reading webapi.xml or schema.graphqls in this module's source code? Neither case needed a single line of extra documentation code - REST and GraphQL both bring their own self-description along from their respective frameworks.

The auto-generated REST schema endpoint

Magento_Webapi generates a Swagger/OpenAPI 2.0 document from every webapi.xml route registered in the system - with zero project-specific configuration. The three service contracts from block 10 automatically appear in it under the same service names chapter 79 already showed on the SOAP WSDL example: RewardRepositoryInterface as mironsoftLoyaltyRewardRepositoryV1, PointsManagementInterface as mironsoftLoyaltyPointsManagementV1, RewardRedemptionManagementInterface as mironsoftLoyaltyRewardRedemptionManagementV1.

# The complete schema of every registered service:
curl -s https://mironsoft.test/rest/en/schema?services=all

# Only the three custom loyalty services:
curl -s 'https://mironsoft.test/rest/en/schema?services=mironsoftLoyaltyRewardRepositoryV1,mironsoftLoyaltyPointsManagementV1,mironsoftLoyaltyRewardRedemptionManagementV1'

Magento Open Source deliberately ships only the raw JSON document, no bundled graphical interface for it. Since it's a standard Swagger/OpenAPI 2.0 format, it imports straight into Swagger UI, Postman, or Insomnia - all three recognize and render the structure without any manual adjustment.

Tipp: Just like webapi.xml/acl.xml themselves, the generated schema endpoint also feeds the config_webservice cache (chapters 80/82) - a freshly added route only appears in the schema after bin/cache-clean config_webservice, even in developer mode.

GraphQL introspection: the schema queries itself

GraphQL needs no separate documentation endpoint - introspection is part of the specification itself. The __schema and __type meta-fields answer the very same /graphql request that also serves loyaltyPointsSummary or redeemLoyaltyReward, and return the full structure of every type registered in chapters 82/83 - LoyaltyPointsSummary, LoyaltyPointsLedgerEntry, LoyaltyReward, RedeemLoyaltyRewardInput, and RedeemLoyaltyRewardOutput included.

query IntrospectRewardType {
  __type(name: "LoyaltyReward") {
    name
    fields {
      name
      description
      type { name kind }
    }
  }
}

Achtung: Magento's GraphQl\Controller\GraphQl nowhere restricts introspection by application mode - __schema/__type work in production mode exactly as they do in developer mode (the one thing Magento treats differently there: requests carrying the operation name IntrospectionQuery are explicitly excluded from query logging). The same openness that lets GraphiQL, Altair, or Insomnia offer automatic autocomplete lets any anonymous caller query this shop's entire schema - every loyalty field included - at any time. Anyone wanting to prevent that on a production system has to actively block it at the network/WAF level; Magento core deliberately doesn't do so on its own.

Discoverability and hardening are two separate questions

The same reasoning that led chapter 86 to two separate rate-limiting approaches for redeemLoyaltyReward and loyaltyRewards applies again here: blocking __schema would only stop a client from discovering the shape of the fields - every field would remain exactly as executable and exactly as much in need of protection as before, GraphQlAuthorizationException (chapters 82/83) and the ThrottleRewardRedemptionPlugin (chapter 86) included, unchanged. Documentation makes legitimate use easier; it replaces none of the safeguards this block built.

All files from this block at a glance

New and changed files from block 10

app/code/Mironsoft/Loyalty/
├── Api/
│   ├── Data/
│   │   ├── RewardInterface.php                          (chapter 79)
│   │   ├── PointsSummaryInterface.php                   (chapter 80)
│   │   └── RewardRedemptionResultInterface.php          (chapter 81)
│   ├── RewardRepositoryInterface.php                    (chapter 79)
│   ├── PointsManagementInterface.php                    (chapter 80)
│   └── RewardRedemptionManagementInterface.php          (chapter 81)
├── Model/
│   ├── Data/
│   │   └── Reward.php                                   (chapter 79)
│   ├── RewardRepository.php                             (chapter 79)
│   ├── PointsManagement.php                             (chapter 80)
│   ├── RewardRedemptionManagement.php                   (chapter 81)
│   ├── RateLimiter/
│   │   └── RedemptionRateLimiter.php                    (chapter 86)
│   └── Resolver/
│       ├── PointsSummary.php                            (chapter 82)
│       ├── RewardCatalog.php                            (chapter 82)
│       ├── DataProvider/
│       │   └── RewardCatalog.php                        (chapter 82)
│       └── RedeemLoyaltyReward.php                      (chapter 83)
├── Plugin/
│   └── Api/
│       └── ThrottleRewardRedemptionPlugin.php           (chapter 86)
├── CustomerData/
│   └── PointsBalance.php                                (chapter 84)
├── etc/
│   ├── di.xml                                           (chapter 79/86, extended)
│   ├── webapi.xml                                       (chapter 80/81)
│   ├── acl.xml                                          (chapter 80, extended)
│   ├── schema.graphqls                                  (chapter 82/83)
│   ├── extension_attributes.xml                         (chapter 79)
│   └── frontend/
│       ├── sections.xml                                 (chapter 84)
│       └── di.xml                                       (chapter 84)
└── view/
    └── frontend/
        └── templates/
            └── customer-data/
                └── points-badge.phtml                   (chapter 84)

Checklist: block 10 summarized

  1. Service contract first (chapter 79): an Api\Data interface plus repository, before any transport layer exists at all.
  2. Register REST (chapters 80/81): webapi.xml with self/force for "mine" routes, dedicated ACL resources for everything beyond that.
  3. Register GraphQL (chapters 82/83): schema.graphqls plus a thin resolver that calls nothing but the same service contract - no second implementation of the same logic.
  4. Translate exceptions (chapter 83): LocalizedException from the business logic gets deliberately remapped to GraphQlInputException/GraphQlNoSuchEntityException in the resolver, or the error message vanishes behind "Internal server error".
  5. The own frontend prefers customer section data (chapter 84) over a dedicated GraphQL request whenever the data is already available in the same request cycle.
  6. Document stability (chapter 85): extension attributes instead of new interface methods, @deprecated instead of a silent meaning change.
  7. Bound abuse (chapter 86): rate limiting at the shared service-contract hook point, not duplicated per transport layer.
  8. Accept discoverability without confusing it for hardening (chapter 87): the REST schema and GraphQL introspection are open to anyone - every prior safeguard still stays in force.

Tipp: The thread running through all nine chapters of this block: RewardRepositoryInterface and RewardRedemptionManagementInterface from chapters 79/81 are never duplicated - the REST route, the GraphQL resolver, the GraphQL mutation, and the rate-limiting plugin all call exactly those same two methods. What actually makes up this block isn't new business logic, but the transport layer - and the accompanying questions of versioning, abuse, and discoverability - built around service contracts that already existed.

Block 11 turns next to this module's configuration, multi-language support, and test coverage - starting with chapter 88, which introduces dedicated configuration types beyond the System/Config/Setting page built in chapter 7.