Headless Adobe Commerce storefronts query the catalog over GraphQL. Build a query visually (or write it by hand): the server processes it with a custom parser written in PHP, validates it against a fixed schema, enforces depth and complexity limits, then executes it with batched resolvers. Next to the response you see the execution plan and the timings.
Color
Size
Brand
Selected fields
{
products(pageSize: 5) {
total_count
page_info { current_page page_size total_pages }
items {
sku
name
price_range {
minimum_price {
regular_price { value currency }
final_price { value currency }
}
}
categories { name url_key }
}
}
}type Query {
products(search: String, filter: ProductAttributeFilterInput,
pageSize: Int = 20, currentPage: Int = 1,
sort: ProductAttributeSortInput): Products
}
type Products {
items: [ProductInterface] total_count: Int
page_info: SearchResultPageInfo aggregations: [Aggregation]
}
type ProductInterface {
uid: ID sku: String name: String stock_status: ProductStockStatus
color: String size: String brand: String price_range: PriceRange
categories: [CategoryTree] related_products: [ProductInterface]
}
type CategoryTree { uid: ID name: String url_key: String product_count: Int }
input ProductAttributeFilterInput {
category_uid: FilterEqualTypeInput color: FilterEqualTypeInput
size: FilterEqualTypeInput brand: FilterEqualTypeInput
price: FilterRangeTypeInput
}
input ProductAttributeSortInput { relevance: SortEnum name: SortEnum price: SortEnum }The request is text that the server does not run but parses: the lexer splits it into tokens, the parser builds a syntax tree, and the validator checks it against the fixed schema (existing fields, correct argument types, the rules for leaf and composite fields). There is no eval and no dynamic class or method name: only fields fixed in the schema are resolved, by fixed resolvers.
The biggest risk of a public GraphQL endpoint is the expensive query: a few lines of text that, through nested lists, would fetch thousands of objects. So two limits run BEFORE execution: depth (at most 6 levels here) and complexity, where every field is multiplied by the expected size of the lists above it. Adobe Commerce also enforces depth and complexity limits on GraphQL requests.
The N+1 problem: if categories or related products were queried separately per product, a page of 20 would run 20 extra queries per field. The executor therefore walks level by level and calls a field resolver once for all parents on that level (the DataLoader pattern); Magento solves the same with batch resolvers.
The demo implements a well-defined subset: a single query operation, fields, aliases and literal arguments. Variables, fragments, directives, mutations and introspection are left out. They are needed for a complete language, but would grow the parser and the attack surface without enriching the point (validation, limits, batched execution).
This site uses Google Analytics to measure visits. This requires your consent - see the privacy policy for details. Privacy Policy