Scalar and Complex Types, Defining Custom Input Types
Scalar and Complex Types, Defining Custom Input Types
~8 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
After the simple string query from chapter 5, it's now time for complex types - custom object types with multiple fields - and input types, which accept structured arguments instead of loose scalars.
The built-in scalar types
GraphQL ships five built-in scalar types that every schema builds on: Int, Float, String, Boolean, and ID (a string semantically marked as a unique identifier). Magento itself doesn't define additional custom scalars for things like dates - timestamps are transferred as formatted String values, not as a dedicated DateTime scalar. The events project starting in block 4 follows this same convention.
Declaring a custom object type
An example in the warm-up module: a query shopContact that returns a structured object with multiple fields instead of a single string.
type Query {
shopContact: ShopContact
@resolver(class: "Mironsoft\\GraphqlDemo\\Model\\Resolver\\ShopContact")
@doc(description: "Returns the shop's public contact details")
}
type ShopContact @doc(description: "Public contact details of the shop") {
company_name: String
email: String
phone: String
support_hours: [String]
}type ShopContact { ... } is a custom, named GraphQL type - not a PHP interface, just a pure schema declaration. [String] declares a list of strings (chapter 7 covers list semantics in detail).
<?php
declare(strict_types=1);
namespace Mironsoft\GraphqlDemo\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
/**
* Resolves the shopContact query field.
*/
class ShopContact implements ResolverInterface
{
/**
* Returns the shop's static contact details as an array matching the
* ShopContact GraphQL type.
*
* @param Field $field Resolved GraphQL field configuration
* @param mixed $context Resolver context
* @param ResolveInfo $info GraphQL resolve tree info
* @param array|null $value Parent resolver's value, unused here
* @param array|null $args Arguments passed to the shopContact field
* @return array<string, mixed>
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
?array $value = null,
?array $args = null
): array {
return [
'company_name' => 'Mironsoft',
'email' => 'kontakt@mironsoft.de',
'phone' => '+49 30 1234567',
'support_hours' => ['Mon-Fri 9am-5pm'],
];
}
}The key point: the resolver returns an associative array whose keys match the field names from type ShopContact exactly. For each individual field (company_name, email, ...), the default resolver mentioned in chapter 2 then kicks in automatically - custom resolver classes per field are only needed when a field requires its own logic.
Custom input types for structured arguments
Just like object types exist for return values, there are input types for arguments - declared with input instead of type. They may only consist of scalars, enums, and further input types, never regular object types.
input ShopContactFilterInput {
department: String
language: String
}
type Query {
shopContact(filter: ShopContactFilterInput): ShopContact
@resolver(class: "Mironsoft\\GraphqlDemo\\Model\\Resolver\\ShopContact")
}In the resolver, such an input type ends up as a nested array in $args['filter'] - $args['filter']['language'] ?? null then reads the individual value. This pattern - one input type as the single structured argument instead of many loose scalar arguments - is standard practice in Magento's own mutations (chapter 16) and is adopted for filtering and sorting in the events project starting in chapter 14.
Tipp: When choosing between "several loose arguments" and "one input type", a simple rule of thumb applies: once you have three or more related arguments, or as soon as a field should be reusable (e.g. in both a mutation and a query), a dedicated input type pays off.
Chapter 7 covers how to correctly model required fields (!), nullable fields, and lists in the schema - a topic deliberately simplified here for ShopContact.