Let me start with an example, a very standard CRUD API:
@strawberry.type
class User
name: str
birthday: date
...
@strawberry.field
async def something(self) -> Something
@strawberry.input
class UserInput
name: str = UNSET
birthday: date = UNSET
...
@strawberry.type
class Query:
@strawberry.field
get_user(id: ID) -> User:
...
@strawberry.type
class Mutation:
@strawberry.mutation
create_user(user: UserInput) -> User:
...
@strawberry.mutation
update_user(id: ID, user: UserInput) -> User:
..
The types User
and UserInput
are essentially the same thing all over again -- Except the inputs don't have resolvers
Keeping the fields and docs in sync is just boring repetitive work.
Would be great if we could reuse the same type declaration in our arguments, and strawberry would just create an input type in the schema under the hood containing only the dataclass fields
@strawberry.type
class Mutation:
@strawberry.mutation
create_user(user: User) -> User:
...
---
type Mutation {
createUser(user: UserInput!): User!
}
GraphQL-Kotlin does that
IMHO this is a simple and reasonable approach
Another suggestion is to keep the Main/Input types distinct, but generate the Type.Input automatically:
User.Input
UNSET
or removed entirelySomeTime
, it gets replaced by SomeTypeInput
strawberry.field()
strawberry.field(
input_options=InputFieldOptions(
keep=True, # Keep/discard this field in the Input type,
type=DataType, # Modify the field type. e.g., a NestedObject-type field might be replaced by an ID in an input
default=DataType() # Uses this as the default value
default_factory=lambda: DataType() # Uses this as the factory
description="Same field, now in an input"
)
)
This would look like this:
@strawberry.type
class Mutation:
@strawberry.mutation
create_user(user: User.Input) -> User:
...
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too