strawberry-graphql / strawberry

A GraphQL library for Python that leverages type annotations πŸ“
https://strawberry.rocks
MIT License
3.9k stars 514 forks source link

How to serialize Strawberry models #3565

Open mecampbellsoup opened 1 month ago

mecampbellsoup commented 1 month ago

I'm writing some integration tests that use an HTTP client to hit our GQL API like so:

resp = await client.post(
        "/api/",
        headers={"Content-Type": "application/json"},
        json={
            "query": query,
            "variables": {"form": strawberry.asdict(saml_configuration_form)},
        },
    )

In this example, saml_configuration_form is a strawberry input type:

@strawberry.experimental.pydantic.input(model=SAMLConfigurationPyd, all_fields=True)
class SAMLConfigurationForm:
    pass

This gets me halfway there, but strawberry.asdict seems to be limited to snake-casing (or rather, limited to however the fields are cased on the SAMLConfigurationPyd model in this example).

Would it be possible to support something like:

from pydantic.alias_generators import to_camel

strawberry.asdict(saml_configuration_form, alias_generator=to_camel)

That way I can easily inflect the serialized form's keys.

Upvote & Fund

Fund with Polar

patrick91 commented 1 month ago

@mecampbellsoup I think adding support for (un)snake casing would be nice, but we would need to do via a schema configuration, since that depends on how the schema has been configured 😊

mecampbellsoup commented 1 month ago

@mecampbellsoup I think adding support for (un)snake casing would be nice, but we would need to do via a schema configuration, since that depends on how the schema has been configured 😊

What API are you envisioning? (I know I opened the issue so it's rich for me to ask you that but, humor me! πŸ˜†)

Then at the object type level might it be configurable similarly to Pydantic's model_config or something?

class StorageClassPyd(PydanticModel):
    model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
patrick91 commented 1 month ago

I was thinking something like this:

@strawberry.input
class Something:
    name: str
    something_else: str

data = Something(name="ABC", something_else="ABC")

strawberry.asdict(data, config={"auto_camel_case": True}) # this would be the same config passed to the schema

but while writing this I realised that asdict wasn't really made for this use case, the camelcase behaviour is something that's done on the schema level most of the time, so maybe we should have something like schema.serialize(data), but I'm not convinced it's a good/useful feature to have.

What's your reasoning behind not passing a dict to your test? 😊

mecampbellsoup commented 1 month ago

What's your reasoning behind not passing a dict to your test? 😊

Laziness!

I just thought that this type of camel case to snake case conversion was happening internally quite a bit, since the FE JSON is typically formatted w/ camelCase keys, and all the Python BE types/code tends to assume snake_case, so I was hoping to grok an easy way to replicate that observed behavior.

I like using the strawberry types as a starting point though because that's the "public facing API", so in integration tests passing form data to GQL resolvers, it feels like the right thing (as opposed to e.g. using the Pydantic types).

To your point though, we can pass dictionaries in tests.