GraphQL / Basic: language and response contracts / Lesson 3
Queries, arguments and variables
Build reusable named operations and distinguish omitted input from explicit null.
On this page
Lesson goals
- Declare variables that satisfy argument positions and keep values out of query text.
- Predict argument defaults, required inputs and alias response keys.
Keep operation structure stable
A query selects fields and passes named arguments. The operation name identifies a particular use case, while variables carry changing values. This separation makes documents reviewable, cacheable at the document level and easier to identify in traces. It also avoids constructing language syntax by concatenating user text. Variables do not automatically sanitize downstream SQL or enforce authorization; they give GraphQL a typed input boundary. The resolver must still call its data source with that source’s safe parameterization and the caller’s permitted scope.
Pair a typed document with a JSON map
Assume course(id: ID!) returns the synthetic visible course c1. The variable declaration requires a non-null ID and the JSON map supplies its value. The operation can be reused for another allowed identifier without changing the document text. A missing required variable fails input coercion before field execution. Preserve types when serializing JSON: a boolean must be true rather than the string "true" for a Boolean variable. Exact error wording varies by implementation, so classify the stage and field instead of matching one library message globally.
query CourseCard($id: ID!) {
course(id: $id) { id title }
}
Send variables {"id":"c1"}. The document and variables are separate members of an HTTP request body when HTTP is used.
Omission is not an explicit null value
Optional arguments and variables may have defaults. Omitting a value allows the relevant default rules to apply; explicitly providing null communicates a value and does not mean use the default. This distinction becomes especially important for update inputs, where omission can mean preserve and null can mean clear. A variable’s declared type must also be valid at its argument position, with specification rules accounting for applicable defaults. Prefer simple compatible declarations in introductory operations rather than relying on subtle nullable-variable exceptions without tests.
Use aliases when argument sets differ
Aliases change response keys, not the schema field’s identity or permission rules. Selecting course twice with different IDs under the same response name creates a field-merging conflict. Distinct aliases communicate two separate result positions. The server may resolve them concurrently and no ordering guarantee should be inferred from their placement in the query. The fixture below assumes both objects are visible and have the stated titles. If one lookup is unavailable, its nullable result can be null without necessarily removing the other object.
query CompareCards {
first: course(id: "c1") { title }
second: course(id: "c2") { title }
}
{"data":{"first":{"title":"Graph foundations"},"second":{"title":"Graph practice"}}}
For titles Graph foundations and Graph practice, first and second appear as distinct JSON keys. Aliases are not a cache or access boundary.
Review documents with their variable fixtures
A document that validates with one fixture can still fail with a missing variable, a wrong JSON type or an input outside an application limit. Keep tests for required, omitted, null and boundary values next to the operation. If a document contains multiple operations, the request must choose the intended operation by name. Do not place sensitive variable values in URLs merely to make a request easier to inspect; logs and browser history can retain them. Transport choices and document correctness require separate reviews.
Common errors and fixes
A String variable is used where ID! is required
- Why it happens
- Similar serialized values were mistaken for compatible declared types.
- How to fix it
- Declare the variable with the required compatible GraphQL type.
- Prevent it next time
- Validate documents in addition to inspecting JSON samples.
Explicit null unexpectedly clears a field
- Why it happens
- The client used null to mean omit.
- How to fix it
- Remove the member when preserve is the documented operation.
- Prevent it next time
- Test omitted, null and concrete input separately.
Two differently parameterized fields conflict
- Why it happens
- Both selections have the same response key.
- How to fix it
- Assign clear aliases for the distinct selections.
- Prevent it next time
- Review field merging while composing documents.
Check your understanding
1. An optional limit defaults to 20. Is sending null identical to omitting limit?
Show worked solution
No. Omission lets a defined default apply; explicit null is a supplied null and must satisfy the argument’s contract and resolver policy. Write fixtures for omitted, null, zero and a positive limit. If the API forbids null, represent that through an appropriate schema and clear validation rather than silently substituting values in unrelated clients.
2. Why does variable use not make string-built SQL safe automatically?
Show worked solution
GraphQL validates the variable against its input type, but the resolver controls how it reaches the source. Concatenating that string into SQL can still be unsafe. Use the database driver’s parameter binding and apply business authorization. Keep the operation document stable for review, but test the downstream adapter independently because each boundary has different semantics.
Key takeaways
- Stable documents and typed variables simplify review without replacing source safety.
- Omitted values, nulls and defaults are distinct contract cases.