{ }
type
GraphQL · Schema-Design · Input Types · Custom Scalars · Validation
Input Types vs. Custom Scalars:
Wann welcher Ansatz?

Im GraphQL-Schema-Design führt die Frage nach Input Types versus Custom Scalars regelmäßig zu Diskussionen. Beide lösen ähnliche Probleme auf unterschiedliche Art. Der Unterschied liegt nicht in der Leistungsfähigkeit, sondern im semantischen Anspruch: Beschreibt der Typ eine Struktur oder einen Wertebereich?

13 Min. Lesezeit Input Types · Custom Scalars · Validation · Enums · Magento Schema-Design · Typsicherheit · Serverseitige Validierung

1. Die Grundfrage: Struktur oder Wertebereich?

Die Entscheidung zwischen Input Types und Custom Scalars lässt sich auf eine einfache Grundfrage reduzieren: Ist der Wert, den eine Mutation oder Query entgegennimmt, ein strukturiertes Objekt mit mehreren Feldern – oder ein einzelner Wert mit einem spezifischen Format und Wertebereich? Input Types beschreiben die erste Kategorie, Custom Scalars die zweite. Beide können Validierungslogik enthalten, aber sie tun es auf grundlegend verschiedene Arten und an verschiedenen Stellen im System.

Das klingt wie eine technische Unterscheidung ohne praktische Konsequenz, ist aber entscheidend für die Lesbarkeit des Schemas und die Art der Fehlermeldungen, die Clients erhalten. Ein schlecht gewählter Custom Scalar, der eigentlich ein Input Type sein sollte, macht das Schema schwerer zu verstehen und schiebt Validierungslogik in den Resolver, wo sie nicht hingehört. Ein Input Type, der eigentlich ein Custom Scalar sein sollte, erzeugt unnötige Schachtelungstiefe und erschwert die Nutzung aus Client-Perspektive.

2. Input Types: Strukturierte Daten als Typen im Schema

Ein Input Type ist ein benannter Typ im GraphQL-Schema, der ausschließlich als Eingabe genutzt werden kann – er darf nicht in Output-Feldern auftauchen. Das unterscheidet ihn von regulären Objekt-Typen, die nur als Ausgabe verwendet werden können. Input Types eignen sich für alle Fälle, in denen mehrere zusammengehörige Felder als Einheit an eine Mutation oder einen Query-Resolver übergeben werden sollen. Typische Beispiele: Adressdaten, Filter-Kombinationen, Paginierungsparameter oder Produktkonfigurationen.

Der Hauptvorteil von Input Types liegt in der Selbstdokumentation: Das Schema zeigt sofort, welche Felder in einem bestimmten Kontext erwartet werden, welche davon optional sind und welche Typen sie haben. In Magento nutzt das System Input Types extensiv: ProductAttributeFilterInput, CustomerInput und AddProductsToCartInput sind etablierte Beispiele, die zeigen, wie strukturierte Eingaben in einer komplexen API sauber modelliert werden.


# Input Type example: structured address data for checkout mutations
# Multiple related fields grouped as a reusable input type

input AddressInput {
  firstname: String!
  lastname: String!
  street: [String!]!       # array: street lines
  city: String!
  postcode: String!
  country_code: String!
  telephone: String
  company: String
  vat_id: String
  save_in_address_book: Boolean
}

# Input Type for product filter: reusable, well-documented
input ProductAttributeFilterInput {
  category_id: FilterEqualTypeInput
  price: FilterRangeTypeInput
  sku: FilterEqualTypeInput
  name: FilterMatchTypeInput
}

input FilterRangeTypeInput {
  from: String
  to: String
}

# Usage in mutation
type Mutation {
  setBillingAddressOnCart(
    input: SetBillingAddressOnCartInput!
  ): SetBillingAddressOnCartOutput
}

3. Custom Scalars: Semantisch bedeutungsvolle Einzelwerte

Custom Scalars erweitern die eingebauten Skalare (String, Int, Float, Boolean, ID) um domänenspezifische Werttypen. Ein Email-Scalar ist ein String mit einer spezifischen Struktur und einem Wertebereich, der durch das E-Mail-Format definiert ist. Ein DateTime-Scalar ist ein String im ISO-8601-Format. Ein URL-Scalar ist ein String mit gültigem URL-Schema. Die Validierung erfolgt im Scalar-Resolver auf dem Server, nicht im Feld-Resolver.

Der entscheidende Vorteil: Custom Scalars kommunizieren Semantik direkt im Schema. Ein Feld vom Typ Email ist selbstdokumentierend – jeder Client-Entwickler versteht sofort, was erwartet wird, ohne die Dokumentation zu lesen. Ein Feld vom Typ String, das eine E-Mail-Adresse erwartet, ist dagegen nur durch Dokumentationskommentare verständlich. Custom Scalars funktionieren auch als Output-Typen, was Input Types nicht können – das macht sie zur richtigen Wahl für Felder, die sowohl gelesen als auch geschrieben werden.


# Custom Scalar definitions — semantic types for domain-specific values
# Server-side validation happens in the scalar resolver

scalar Email       # validated RFC 5322 email address
scalar URL         # validated absolute URL with scheme
scalar DateTime    # ISO 8601 datetime string
scalar PhoneE164   # E.164 international phone number format
scalar Money       # decimal with 2 fractional digits
scalar SKU         # alphanumeric product identifier pattern

# Usage: scalars work as both input and output types
type Customer {
  email: Email!                  # output: read and write
  phone: PhoneE164               # output: read and write
  created_at: DateTime!          # output: read only
}

type Mutation {
  createCustomer(
    email: Email!                # input: validated at scalar level
    phone: PhoneE164
  ): Customer
}

# Input Type for the same use case — more verbose, less semantic
# (only use when multiple related fields justify the structure)
input CustomerCreateInput {
  email: Email!
  phone: PhoneE164
  firstname: String!
  lastname: String!
}

4. Validierung: Wo Input Types und Scalars unterschiedlich ansetzen

Bei Input Types findet die Validierung auf Feldebene statt: Pflichtfelder, Typen und die grundlegende Struktur werden durch das GraphQL-Execution-Framework geprüft, bevor der Resolver aufgerufen wird. Darüber hinausgehende Validierungslogik – "Das Datum muss in der Zukunft liegen" oder "Der Preisbereich muss positive Zahlen enthalten" – muss im Resolver implementiert werden. Das ist korrekt, weil diese Regeln geschäftliche Bedeutung haben, die das Schema allein nicht ausdrücken kann.

Bei Custom Scalars findet die Validierung im Scalar-Resolver statt, bevor der Feld-Resolver aufgerufen wird. Ein Email-Scalar, der einen ungültigen Wert erhält, schlägt sofort mit einem Schema-Validierungsfehler fehl – ohne den Resolver zu berühren. Das ist effizienter und produziert konsistentere Fehlermeldungen. Die Grenze liegt dort, wo Validierungsregeln vom Kontext abhängen: "Diese E-Mail-Adresse ist bereits registriert" ist kein Scalar-Fehler, sondern ein Anwendungsfehler im Resolver.

5. Enums als dritte Option: Wenn der Wertebereich endlich ist

Enums sind die natürliche Wahl, wenn der Wertebereich eines Feldes endlich und im Schema vollständig bekannt ist. Anstatt einen String mit dem Kommentar "erlaubte Werte: asc, desc" zu verwenden, definiert man einen Enum SortDirection { ASC DESC }. Das Schema validiert den Wert automatisch und der Client erhält bei ungültigem Input eine klare Fehlermeldung noch vor dem Resolver-Aufruf.

In Magento sieht man Enums für Sortierrichtungen, Produktsichtbarkeit und Bestellstatus. Der kritische Designunterschied zu Custom Scalars: Ein Enum-Wert ist nicht validierbar in einem Custom-Scalar-Sinne – er ist entweder einer der bekannten Werte oder ungültig. Custom Scalars sind für Wertebereiche, die nicht im Schema aufgezählt werden können: E-Mail-Adressen, URLs und Datumsangaben sind prinzipiell unendlich viele gültige Werte. Enums decken immer dann, wenn die möglichen Werte zur Design-Zeit bekannt und stabil sind.

6. Input Types und Custom Scalars in Magento GraphQL

Magento nutzt Input Types umfassend und Custom Scalars selektiv. Die eingebauten Input Types wie ProductAttributeFilterInput, AddSimpleProductsToCartInput und CustomerAddressInput sind gute Referenzbeispiele für strukturierte Eingaben in einer komplexen E-Commerce-API. Für eigene Module sollte man dieselbe Konvention folgen: Input Type verwenden, wenn eine Mutation mehrere zusammengehörige Parameter hat, und das Input-Objekt mit dem Suffix Input benennen.

Custom Scalars sind in Magento spärlich eingesetzt. Das System nutzt hauptsächlich den eingebauten Typ String für Werte, die semantisch spezifischer sein könnten. In eigenen Modulen kann man Custom Scalars für domänenspezifische Werte definieren – ein SKU-Scalar für das Produktidentifikator-Format oder ein Barcode-Scalar für Barcode-Strings. Die SDL-Definition ist einfach, aber die Resolver-Implementierung in PHP muss die Serialisierungs- und Validierungslogik beinhalten.


# Magento-style input type for a custom module
# Convention: suffix "Input", all related fields grouped

input CreateLeadInput {
  firstname: String!
  lastname: String!
  email: String!          # ideally: Email scalar, but String is common in Magento
  phone: String
  message: String!
  product_sku: String     # reference to a product
  preferred_contact_date: String  # ideally: Date scalar
  store_id: Int
}

# Response type for mutations (not an input type)
type CreateLeadOutput {
  lead_id: ID!
  status: LeadStatus!
  created_at: String!
}

enum LeadStatus {
  PENDING
  CONFIRMED
  CLOSED
  REJECTED
}

type Mutation {
  createLead(input: CreateLeadInput!): CreateLeadOutput
}

type Query {
  # Input type for filter — reusable across queries
  leads(filter: LeadFilterInput, pageSize: Int, currentPage: Int): LeadsOutput
}

input LeadFilterInput {
  status: FilterEqualTypeInput
  created_at: FilterRangeTypeInput
  email: FilterMatchTypeInput
}

7. Code-Generation und Typsicherheit mit beiden Ansätzen

Code-Generation-Tools wie GraphQL Code Generator erzeugen aus Input Types TypeScript-Interfaces, die 1:1 der Schema-Struktur entsprechen. Das bedeutet: Frontend-Entwickler erhalten vollständige Typen für alle Eingabeformulare und Mutations-Aufrufe, ohne diese manuell pflegen zu müssen. Bei Custom Scalars ist das etwas komplexer: Der generierte TypeScript-Typ für einen Custom Scalar ist standardmäßig any, weil der TypeScript-Compiler nicht wissen kann, was der Scalar repräsentiert. Man konfiguriert in der Code-Generator-Config, welcher TypeScript-Typ welchem Scalar entspricht – Email wird zu string, DateTime zu Date oder string.

Der Praxistipp für Teams, die Code-Generation nutzen: Custom Scalars mit sorgfältig definierten TypeScript-Mappings sind der sauberste Weg, Typsicherheit von der Schema-Ebene bis in den Client-Code zu tragen. Ein DateTime-Scalar, der auf TypeScript Date gemapped ist, stellt sicher, dass der Compiler Typfehler erkennt, wenn ein Entwickler versehentlich einen Plain-String dort übergibt.

8. Typische Designfehler und wie man sie vermeidet

Der häufigste Fehler bei Input Types ist das "God Input Object" – ein einziges riesiges Input-Objekt, das alle möglichen Felder einer Mutation als optional enthält. Das klingt flexibel, ist aber schwer zu verstehen und schwer zu validieren. Welche Felder sind für welchen Use Case relevant? Welche Kombinationen sind sinnvoll? Besser: Separate Input Types für unterschiedliche Mutations-Pfade, auch wenn sich Felder überschneiden. Ein CreateCustomerInput und ein UpdateCustomerInput können ähnliche Felder haben, aber verschiedene Non-Null-Anforderungen.

Der häufigste Fehler bei Custom Scalars ist das Erstellen von Scalars für Werte, die eigentlich Enums sein sollten: Ein Status-Scalar mit den Werten "active", "inactive", "pending" ist keine gute Idee, weil der Wertebereich endlich und dem Schema bekannt ist. Dafür gibt es Enums. Custom Scalars sind für Wertebereiche, die nicht sinnvoll aufzuzählen sind. Ein weiterer Fehler: Einen Custom Scalar definieren, aber keine Validierungslogik implementieren. Ein Email-Scalar, der jeden String akzeptiert, ist schlechter als ein einfacher String, weil er falsche Erwartungen weckt.

Szenario Falsch Richtig Grund
E-Mail-Adresse String Email (Custom Scalar) Semantik im Schema sichtbar
Sortierrichtung String (asc/desc) enum SortEnum { ASC DESC } Endlicher Wertebereich
Adresse für Checkout 5 separate Argumente AddressInput Zusammengehörige Felder
Datum-Filterbereich String (undokumentiert) DateTime Scalar Format erzwingen und dokumentieren
Status-Wert Custom Scalar Status enum OrderStatus { ... } Wertebereich ist endlich und bekannt

9. Direkte Gegenüberstellung: Wann was?

Die Entscheidungsregel ist einfach, wenn man sie einmal verinnerlicht hat: Input Type verwenden, wenn mehrere zusammengehörige Felder als Einheit übergeben werden und wenn die Struktur selbst Teil der API-Dokumentation sein soll. Custom Scalar verwenden, wenn ein einzelner Wert eine spezifische Semantik hat, die über "ist ein String" hinausgeht, und wenn dieser Wert auf Scalar-Ebene validiert werden kann. Enum verwenden, wenn der Wertebereich endlich und zur Design-Zeit vollständig bekannt ist.

In der Praxis ist die häufigste korrekte Kombination: Ein Input Type enthält Felder, die Custom Scalars oder Enums sind. Eine CreateCustomerInput hat ein Feld email: Email! (Custom Scalar), ein Feld status: CustomerStatus (Enum) und ein Feld address: AddressInput (nested Input Type). Diese Kombination nutzt alle drei Konzepte an der richtigen Stelle und produziert ein Schema, das ohne Kommentare selbsterklärend ist.

Input Types vs. Custom Scalars — Das Wichtigste auf einen Blick

Input Types

Für mehrere zusammengehörige Felder als Einheit. Nur als Eingabe nutzbar. Validierung im Resolver – ideal für Adressen, Filter, Paginierung.

Custom Scalars

Für Einzelwerte mit spezifischem Format und Wertebereich. Als Eingabe und Ausgabe nutzbar. Validierung im Scalar-Resolver – ideal für E-Mail, URL, DateTime.

Enums

Für endliche, bekannte Wertebereiche. Schema-Validierung automatisch. Besser als Custom Scalar für Status-Werte und Richtungsangaben.

Kombination

Input Types enthalten Custom Scalars und Enums als Felder – das produziert selbstdokumentierende Schemata ohne überflüssige Kommentare.

10. Zusammenfassung

Input Types, Custom Scalars und Enums sind keine Alternativen, die sich gegenseitig ausschließen, sondern Werkzeuge für verschiedene Designprobleme. Input Types strukturieren zusammengehörige Eingabefelder und machen Mutations lesbar. Custom Scalars machen den Wertebereich einzelner Felder explizit und validierbar auf Schema-Ebene. Enums schließen endliche Wertebereiche im Schema ab. Wer diese drei Konzepte bewusst einsetzt, produziert Schemata, die ohne extensive Dokumentation verständlich sind.

In Magento-Projekten ist der häufigste Nachholbedarf im Bereich Custom Scalars: Viele Felder, die semantisch bedeutungsvolle Werte enthalten (E-Mail, URL, Datum), sind als String modelliert. Das ist nicht falsch, aber eine verpasste Gelegenheit, das Schema selbsterklärend zu machen. Für eigene Module lohnt es sich, Custom Scalars für domänenspezifische Werte zu definieren – der Aufwand ist gering, der Nutzen für die Lesbarkeit und Validierbarkeit des Schemas ist dauerhaft.

11. FAQ: Input Types vs. Custom Scalars – Wann was?

1Unterschied Input Type vs. Custom Scalar?
Input Types sind strukturierte Objekte mit mehreren Feldern. Custom Scalars sind Einzelwerte mit spezifischem Format und Scalar-Level-Validierung.
2Custom Scalar als Output-Typ nutzbar?
Ja. Custom Scalars funktionieren als Input und Output. Input Types nur als Eingabe – sie dürfen nicht in Output-Feldern vorkommen.
3Enum statt Custom Scalar?
Immer wenn der Wertebereich endlich und zur Design-Zeit bekannt ist. Status, Richtungen, Typen → Enum. E-Mail, URL, Datum → Custom Scalar.
4Wo findet Custom Scalar Validierung statt?
Im Scalar-Resolver, bevor der Feld-Resolver aufgerufen wird. Effizienter als Resolver-Validierung – ungültige Werte werden früh abgefangen.
5Custom Scalars in Input Type-Feldern?
Ja, empfohlen: CreateCustomerInput mit email: Email! (Scalar), address: AddressInput (nested Input) und status: CustomerStatus (Enum) – alle Konzepte an der richtigen Stelle.
6Custom Scalar in Magento definieren?
In schema.graphqls mit 'scalar Email', Resolver implementiert CustomScalarInterface – Serialisierung, Parsing und Literalverarbeitung definieren.
7Was ist ein God Input Object?
Ein riesiges Input-Objekt mit allen möglichen optionalen Feldern. Schwer zu verstehen und zu validieren. Besser: separate Input Types für verschiedene Use Cases.
8Custom Scalars bei Code-Generation?
Standard-Typ ist 'any'. TypeScript-Mapping in der Generator-Konfiguration: Email → string, DateTime → Date. Ermöglicht End-to-End-Typsicherheit bis in den Client-Code.
9Für jeden Wert einen Custom Scalar?
Nur wenn Validierung und Semantik wichtig sind: E-Mail, URL, DateTime, domänenspezifische Formate ja. Beliebige Strings ohne Formatanforderung → String reicht.
10Warum nutzt Magento wenige Custom Scalars?
Historisch gewachsen – viele Felder wurden als String modelliert. Für eigene Module empfiehlt sich die Einführung von Custom Scalars für domänenspezifische Werte.