strawberry icon indicating copy to clipboard operation
strawberry copied to clipboard

Issues with strawberry.UNSET

Open ThirVondukr opened this issue 1 year ago • 7 comments

strawberry.UNSET doesn't make parameters optional

It's not possible to use strawberry.UNSET for optional parameters:

@strawberry.input
class StrawberryUnset:
    a: int = strawberry.UNSET
    b: int = strawberry.UNSET


@strawberry.type
class Query:
    @strawberry.field
    async def test(self, input: StrawberryUnset) -> None:
        return None
query GetTest {
  test(input: {}) # fails: a and b weren't provided
}

Would fail because a and b are required.

Query to _service.sdl fails custom sentinel object is used in place of strawberry.UNSET:

_UNSET = object()

@strawberry.federation.input
class StrawberryUnset:
    a: int = _UNSET
    b: int = _UNSET

System Information

  • Strawberry version (if applicable): 0.127.3

Additional Context

Code Reference: https://gitlab.com/ThirVondukr/strawberry-info-warning/-/blob/unset/tests/test_error.py

ThirVondukr avatar Aug 31 '22 01:08 ThirVondukr

@ThirVondukr I think you need to mark the fields as optional as well:

@strawberry.input
class StrawberryUnset:
    a: Optional[int] = strawberry.UNSET
    b: Optional[int] = strawberry.UNSET

otherwise the GraphQL validation will complain 😊

patrick91 avatar Aug 31 '22 09:08 patrick91

@patrick91 I think there's a use case for a non-null optional field, but I don't know if graphql spec allows that 🤔 Could be something like this:

@strawberry.input
class BookUpdate:
    title: str = strawberry.UNSET
    published_at: Optional[datetime] = strawberry.UNSET

This has benefit of checking all of the values for strawberry.UNSET and not checking some fields for None and some for UNSET in code.

ThirVondukr avatar Aug 31 '22 10:08 ThirVondukr

I wonder if that's something we can provide, or at least allow, the GraphQL spec doesn't allow it, so it would be something we do in our codebase, but I'm unsure how to do that :)

patrick91 avatar Aug 31 '22 10:08 patrick91

Main issue (at least for me) is that implementing partial updates is kind of awkward

ThirVondukr avatar Aug 31 '22 10:08 ThirVondukr

@strawberry.input
class BookUpdate:
    title: str = None
    published_at: datetime | None = strawberry.UNSET


@strawberry.type
class Mutation:
    async def book_update(
        self,
        id: strawberry.ID,
        input: BookUpdate,
    ) -> BookType:
        book = await fetch_book_somehow(id)

        if input.title is None:
            book.title = input.title

        if input.published_at is strawberry.UNSET:
            book.published_at = input.published_at

        ...

ThirVondukr avatar Aug 31 '22 10:08 ThirVondukr

FYI I think this proposal should still be implemented: https://github.com/strawberry-graphql/strawberry/issues/872

jkimbo avatar Aug 31 '22 10:08 jkimbo

@jkimbo It seems that was the case ~10 months ago, it worked in my old project which used strawberry 0.93.4 But all non-nullable values are indeed required to be present inside of an input by graphql spec

ThirVondukr avatar Aug 31 '22 10:08 ThirVondukr