Using the Built-In GraphQL Interface: Endpoint, First Queries With a GraphQL Client
Using the Built-In GraphQL Interface: Endpoint, First Queries With a GraphQL Client
~6 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
Before writing any custom queries, it helps to take a practical look at what already works: the existing /graphql endpoint against your own development shop. This sharpens the feel for the request/response format before chapter 4 sets up the first custom module.
Finding the endpoint
The GraphQL endpoint lives under the shop's base URL, path /graphql - in this project's local setup, that's e.g. https://mironsoft.test/graphql. There is no separate port and no separate domain; the endpoint runs through the same Docker container as the regular storefront.
Tools for first queries
Three approaches work well for experimenting, with no custom code at all:
- curl - always available, great for quick checks and for later CI scripts.
- A dedicated GraphQL client such as Altair, Insomnia, or Postman's GraphQL mode - more comfortable thanks to syntax highlighting, schema introspection, and autocomplete.
- Automated tests against
GraphQlAbstract- covered in depth in chapter 24, kept purely manual here for now.
curl -s https://mironsoft.test/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ storeConfig { store_code base_currency_code } }"}' | jqThe request body is plain JSON with a query field (string) and optionally variables (an object) as well as operationName - more on that shortly. The response is JSON too, with a data field for successful fields and optionally errors for failed ones.
Schema introspection: querying the schema itself
GraphQL schemas are self-describing - the schema can be explored via an introspection query, which is exactly what GraphQL clients use for autocomplete:
query {
__type(name: "ProductInterface") {
name
fields {
name
type { name kind }
}
}
}In a GraphQL client such as Altair, one click on "Docs" makes the entire merged schema (chapter 2) searchable - including all core types such as ProductInterface, CustomerOutput, or CartItemInterface.
Variables instead of string concatenation
Values don't belong directly in the query string, but in a separate variables object - this prevents injection-like mistakes and makes queries reusable:
{
"query": "query GetProduct($sku: String!) { products(filter: { sku: { eq: $sku } }) { items { name price_range { minimum_price { final_price { value } } } } } }",
"variables": { "sku": "24-MB01" }
}Achtung: eq, match, in, and friends are operators of the reusable core type FilterTypeInput - this pattern resurfaces later in this series for the custom events filter (chapter 14), instead of reinventing a custom filter type.
Reading error responses correctly
A GraphQL response can contain both data and errors at the same time - partial failures on individual fields don't rule out successful sibling fields. Every error carries a category inside extensions that reveals what kind of error it is - more on that in chapter 19 and chapter 25.
{
"errors": [
{
"message": "Field \"typo_field\" doesn't exist on type \"Query\"",
"extensions": { "category": "graphql" }
}
]
}Tipp: For quick manual tests against the local development environment, it's worth keeping an alias or a small .http file in the project - that way, the same requests end up under version control instead of scattered terminal history.
With a feel for the request format, introspection, and error format in hand, block 2 moves on to the first custom query in a custom module.