|
| 1 | +--- |
| 2 | +title: 0.279.0 Breaking Changes |
| 3 | +slug: breaking-changes/0.279.0 |
| 4 | +--- |
| 5 | + |
| 6 | +# v0.279.0 Breaking Changes |
| 7 | + |
| 8 | +This release changes the `strawberry.Maybe` type definition to provide a more |
| 9 | +consistent and intuitive API for handling optional fields. |
| 10 | + |
| 11 | +## What Changed |
| 12 | + |
| 13 | +The `Maybe` type definition has been changed from: |
| 14 | + |
| 15 | +```python |
| 16 | +Maybe: TypeAlias = Union[Some[Union[T, None]], None] |
| 17 | +``` |
| 18 | + |
| 19 | +to: |
| 20 | + |
| 21 | +```python |
| 22 | +Maybe: TypeAlias = Union[Some[T], None] |
| 23 | +``` |
| 24 | + |
| 25 | +## Impact on Your Code |
| 26 | + |
| 27 | +### Type Annotations |
| 28 | + |
| 29 | +If you were using `Maybe[T]` and expecting to handle explicit `null` values, you |
| 30 | +now need to explicitly declare this with `Maybe[T | None]`: |
| 31 | + |
| 32 | +```python |
| 33 | +# Before (0.278.0 and earlier) |
| 34 | +field: strawberry.Maybe[str] # Could handle Some(None) |
| 35 | + |
| 36 | +# After (0.279.0+) |
| 37 | +field: strawberry.Maybe[str] # Only handles Some("value") or None (absent) |
| 38 | +field: strawberry.Maybe[str | None] # Handles Some("value"), Some(None), or None |
| 39 | +``` |
| 40 | + |
| 41 | +### Runtime Behavior |
| 42 | + |
| 43 | +The runtime behavior changes to provide more consistent field checking: |
| 44 | + |
| 45 | +- `Maybe[str]` now represents "field present with non-null value" or "field |
| 46 | + absent" |
| 47 | +- `Maybe[str | None]` represents "field present with value", "field present but |
| 48 | + null", or "field absent" |
| 49 | + |
| 50 | +This means `Maybe[str]` can no longer receive explicit `null` values - they will |
| 51 | +cause a validation error. |
| 52 | + |
| 53 | +### Consistent Field Checking |
| 54 | + |
| 55 | +This change provides a single, consistent way to check if a field was provided, |
| 56 | +regardless of whether the field allows null values: |
| 57 | + |
| 58 | +```python |
| 59 | +@strawberry.input |
| 60 | +class UpdateUserInput: |
| 61 | + # Can be provided with a value or not provided at all |
| 62 | + name: strawberry.Maybe[str] |
| 63 | + |
| 64 | + # Can be provided with a value, provided as null, or not provided at all |
| 65 | + phone: strawberry.Maybe[str | None] |
| 66 | + |
| 67 | + |
| 68 | +@strawberry.mutation |
| 69 | +def update_user(input: UpdateUserInput) -> User: |
| 70 | + # Same checking pattern for both fields |
| 71 | + if input.name is not None: # Field was provided |
| 72 | + user.name = input.name.value # Type checker knows this is str |
| 73 | + |
| 74 | + if input.phone is not None: # Field was provided |
| 75 | + user.phone = input.phone.value # Type checker knows this is str | None |
| 76 | +``` |
| 77 | + |
| 78 | +The key benefit is that `if field is not None` now consistently means "field was |
| 79 | +provided" for all Maybe fields. |
| 80 | + |
| 81 | +## Migration |
| 82 | + |
| 83 | +### Automatic Migration |
| 84 | + |
| 85 | +Strawberry provides a codemod to automatically update your code: |
| 86 | + |
| 87 | +```bash |
| 88 | +strawberry upgrade maybe-optional |
| 89 | +``` |
| 90 | + |
| 91 | +The codemod will automatically convert `Maybe[T]` to `Maybe[T | None]` to |
| 92 | +maintain the previous behavior. |
| 93 | + |
| 94 | +### Manual Migration |
| 95 | + |
| 96 | +Review your `Maybe` usage and decide whether you need the union type: |
| 97 | + |
| 98 | +```python |
| 99 | +# If you only need "present" vs "absent" (most common case) |
| 100 | +field: strawberry.Maybe[str] |
| 101 | + |
| 102 | +# If you need "present with value", "present but null", and "absent" |
| 103 | +field: strawberry.Maybe[str | None] |
| 104 | +``` |
| 105 | + |
| 106 | +## Why This Change? |
| 107 | + |
| 108 | +After extensive discussion, we decided that changing `Maybe` to `Some[T] | None` |
| 109 | +(instead of `Some[T | None] | None`) provides the best developer experience |
| 110 | +because: |
| 111 | + |
| 112 | +1. **Consistent field checking**: You can always use `if field is not None:` to |
| 113 | + check if a field was provided, regardless of whether the field allows null |
| 114 | + values |
| 115 | + |
| 116 | +2. **Preserves existing behavior**: You can still get the previous behavior by |
| 117 | + using `Maybe[T | None]` when you need to handle explicit nulls |
| 118 | + |
| 119 | +3. **Better type safety**: `Maybe[str]` now properly indicates that the field |
| 120 | + cannot be null, while `Maybe[str | None]` explicitly allows nulls |
| 121 | + |
| 122 | +4. **Cleaner API**: There's now "one true way" to check if a field was provided, |
| 123 | + making the API more intuitive |
| 124 | + |
| 125 | +The new approach provides both simplicity for common cases and flexibility for |
| 126 | +complex scenarios where null handling is needed. |
| 127 | + |
| 128 | +## Need Help? |
| 129 | + |
| 130 | +- See the [Maybe documentation](../types/maybe.md) for comprehensive usage |
| 131 | + examples |
| 132 | +- Check the |
| 133 | + [migration guide](../types/maybe.md#migration-from-previous-versions) for |
| 134 | + detailed migration instructions |
| 135 | +- If you encounter issues, please |
| 136 | + [report them on GitHub](https://github.com/strawberry-graphql/strawberry/issues) |
0 commit comments