Working with Lists and Non-Null
1. Defining List Types
| Notation | Meaning |
|---|---|
[Type] | Nullable list of nullable items |
[Type!] | Nullable list, items required |
[Type]! | Required list, items nullable |
[Type!]! | Required list, items required |
[[Type!]!]! | Nested list (matrix) |
2. Making Lists Required
| Form | Resolver Behavior |
|---|---|
[T]! | Resolver must return an array (may contain nulls) |
[T] | May return null OR array |
3. Making List Items Required
| Form | Resolver Behavior |
|---|---|
[T!] | Items resolve null → error propagates and entire list becomes null |
[T] | Null items kept as nulls in the array |
4. Combining Modifiers
| Recommended | Why |
|---|---|
[T!]! | Most restrictive; clearest contract |
[T!] | List itself optional (no permission, etc.) |
[T] | Avoid — ambiguous nulls everywhere |
5. Understanding Nullability Rules
Resolver returns null on Non-Null field
│
▼
Field result becomes error
│
▼
Propagates UP to nearest nullable ancestor
│
▼
That ancestor becomes null; siblings preserved
6. Returning Empty Lists
| Return | Semantics |
|---|---|
[] | "No items found" |
null | "List unavailable / not applicable" (only on nullable list) |
Note: Prefer empty array over null for collections — clients can iterate without null checks.
7. Handling Null Items
| Scenario | Pattern |
|---|---|
| Sparse data | Use [T] to allow nulls |
| Filtered results | Skip null in resolver, return [T!]! |
| Authorization | Replace with placeholder type or filter out |
8. Paginating Lists
| Strategy | Args |
|---|---|
| Offset | limit, offset |
| Cursor (Relay) | first, after, last, before |
| Page-based | page, perPage |
9. Limiting List Size
| Mechanism | Detail |
|---|---|
Max first | Cap arg in resolver: Math.min(args.first, 100) |
| @cost directive | Cost = first × childCost |
| Validation rule | Reject queries exceeding total cost |